d3重置范围后保留缩放/平移

时间:2014-09-16 17:46:19

标签: d3.js

我有一个<svg>,其宽度是其容器的100%。调整容器大小后,我会更新线性xScale.range()以表示<svg>的新调整大小的宽度。显然,我需要按照zoom.x() documentation中的说明重新应用范围到我的缩放行为:

  

如果以编程方式修改了比例的域或范围,则应再次调用此函数。设置x标度也会将标度重置为1,并将平移重置为[0,0]。

重置scaletranslate是我遇到问题的地方。如果我在调整大小之前已经放大了,我会调用zoom.x( xScale ),现在d3认为图表的比例是1而翻译是0,0因此,我无法缩小或平移。

我处理调整大小的方法是否不正确?

3 个答案:

答案 0 :(得分:9)

看起来最好的策略是缓存比例并翻译值,重置,然后重新应用。为了记录,这段代码(在我的调整大小处理程序中)大致显示了我的解决方案:

// Cache scale
var cacheScale = zoom.scale();

// Cache translate
var cacheTranslate = zoom.translate();

// Cache translate values as percentages/ratio of the full width
var cacheTranslatePerc = zoom.translate().map( function( v, i, a )
{
  return (v * -1) / getFullWidth();
} );

// Manually reset the zoom
zoom.scale( 1 ).translate( [0, 0] );

// Update range values based on resized container dimensions
xScale.range( [0, myResizedContainerWidth] );

// Apply the updated xScale to the zoom
zoom.x( xScale );

// Revert the scale back to our cached value
zoom.scale( cacheScale );

// Overwrite the x value of cacheTranslate based on our cached percentage
cacheTranslate[0] = -(getFullWidth() * cacheTranslatePerc[0]);

// Finally apply the updated translate
zoom.translate( cacheTranslate );


function getFullWidth()
{
  return xScale.range()[1] * zoom.scale();
}

答案 1 :(得分:4)

对于那些偶然发现这个寻找v4解决方案的人来说,使用Philip上面那个针对v3的精彩设置,我采用了一个基于松散的v4解决方案。我展开变量来解释v3用来做它的方式(因为它在v3中更有意义)。 v4没有像v3那样强制X值的能力,所以你必须计算出现有的X然后除以比例(K)。 (可能有更好的方法进行最终计算+在变焦上设置它,但d3-zoom文档在这方面有点混乱)

let transform = d3.zoomTransform(node);
let oldFullWidth = (oldWidth * transform.k);
let newFullWidth = (newWidth * transform.k);

// this is the result you want X to be
let newX = -(newFullWidth * ((transform.x * -1) / oldFullWidth));
// this is just deducting from the existing so you can call .translate
let translateBy = (newX - transform.x) / transform.k;
d3.select(node).call(myZoom.transform, transform.translate(translateBy, 0));

答案 2 :(得分:0)

我仍在D3v3中,其中有我的一个库,并且在这个问题上苦苦挣扎多年。

我认为@Philip解决方案的原理非常出色:由于D3仅在表示平移[0,0]和缩放0时才采用缩放比例,因此请保存缩放参数,然后将缩放比例重置为那个状态。并且在更换秤时,请确保它们也处于重置状态。

我无法让Philip的代码为我工作,可能是因为我需要设置两个维度,或者可能是因为我需要根据新的div大小调整域的大小。但是我想我对他的技术有了很好的概括。

再进一步一步,重置缩放比例并转换缩放行为将导致其将缩放域更改为以恢复重置状态。非常有帮助!

现在我们可以

  • 将比例域乘以新尺寸与旧尺寸的比例
  • 将范围设置为新的div大小
  • 将比例尺(仍未翻译和未缩放但大小不同)放回缩放
  • 还原转换和缩放比例

至少对我有用!

这里是来源,所有输入oldWidtholdHeightnewWidthnewHeight都在屏幕坐标中:

var scale = _zoom.scale(), translate = _zoom.translate();
_zoom.scale(1).translate([0,0]);
var xDomain = _diagram.x().domain(), yDomain = _diagram.y().domain();
_diagram.x()
    .domain([xDomain[0], xDomain[0] + (xDomain[1] - xDomain[0])*newWidth/oldWidth])
    .range([0, newWidth]);
_diagram.y()
    .domain([yDomain[0], yDomain[0] + (yDomain[1] - yDomain[0])*newHeight/oldHeight])
    .range([0, newHeight]);
_zoom
    .x(_diagram.x()).y(_diagram.y())
    .translate(translate).scale(scale);

将库移植到D3v4时,我一定会再检查一次。