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

CQM*_*CQM 4 svg zoom scale d3.js

我有一个带缩放功能的图表.我的主要观察是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)如何做到这一点?洞察力赞赏.

Sup*_*gly 12

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

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

虽然如此,您仍然可以使用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(); 
Run Code Online (Sandbox Code Playgroud)

你可以在这里试试

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

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

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

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

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);
Run Code Online (Sandbox Code Playgroud)

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

因此,为了获得您想要的行为,我们将在y比例上取消默认的缩放行为,而不是每当我们获得缩放或平移时我们将自己修改y比例域:由于缩放行为,我们已经方便地对这些动作进行回调.

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

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

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

d3.extents(filteredData, function(d) { return d.value; });
Run Code Online (Sandbox Code Playgroud)

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

y.domain(yExtent).nice(); 
Run Code Online (Sandbox Code Playgroud)

我在api中发现的很好的方法,因为它是你想要做比例的事情,而d3经常为你做你想做的事情.

一个很好的教程,可以找出一些这样的东西:http://alignedleft.com/tutorials/ 值得逐步完成你认为已经知道的部分.