d3.js 在版本 4 中重写缩放示例

Posted

技术标签:

【中文标题】d3.js 在版本 4 中重写缩放示例【英文标题】:d3.js rewriting zoom example in version4 【发布时间】:2016-11-26 19:59:18 【问题描述】:

Drag and Drop Example

我正在尝试重写上面这个示例的一部分以在我的代码中使用,特别是这一部分:

function centerNode(source) 
        scale = zoomListener.scale();
        x = -source.y0;
        y = -source.x0;
        x = x * scale + viewerWidth / 2;
        y = y * scale + viewerHeight / 2;
        d3.select('g').transition()
            .duration(duration)
            .attr("transform", "translate(" + x + "," + y + ")scale(" + scale + ")");
        zoomListener.scale(scale);
        zoomListener.translate([x, y]);
    

但是,由于 v4 软件包发生了很大变化,因此我陷入了困境。我将 zoomListener 函数编写为

    var zoomListener = d3.zoom()
                 .scaleExtent([0.3,2])
                 .on("zoom", zoomed);

    function zoomed() 
       transform = d3.event.transform;
       console.log(d3.event);
         svg.attr("transform", transform);
     

function centerNode(source)
  t = transform;
  console.log(t);
  x = t.x*t.k; //I only want things to be centered vertically
  y = (t.y + -source.x0)*t.k + (viewerHeight)/2 ;
  svg.transition()
     .duration(duration)
     .attr("transform","translate(" + x + "," + y +")scale(" + t.k + ")");

  transform.scale(t.k); //DOES NOT WORK
  transform.translate([x, y]); //DOES NOT WORK


我知道根据文档,事情已经发生了变化,信息不再存储在我的 zoomListener 上 D3 V4 release note on zoom 我想我只是对如何使用新版本进行操作感到困惑。我的 centerNode 函数的最后几行不起作用,这意味着当我将节点居中时,缩放和平移重置...

有什么建议吗?

【问题讨论】:

coderwall.com/p/psogia/simplest-way-to-add-zoom-pan-on-d3-js 【参考方案1】:

因此,经过大量挖掘和反复试验,我想出了一个非常适合我的目的的答案。请注意,下面的代码只是我的代码的相关部分,而不是整个代码,某些变量是不言自明的,因此不包括它们。 这也在 d3.js 的第 4 版中。

var zoom = d3.zoom()
             .scaleExtent([0.3,2])
             .on("zoom", zoomed);


var svg = d3.select("body")
            .append("svg")
              .attr("width", viewerWidth)
              .attr("height", viewerHeight);

var zoomer = svg.append("rect")
                .attr("width", viewerWidth)
                .attr("height", viewerHeight)
                .style("fill", "none")
                .style("pointer-events", "all")
                .call(zoom);

var g = svg.append("g");

zoomer.call(zoom.transform, d3.zoomIdentity.translate(150,0)); //This is to pad my svg by a 150px on the left hand side

function zoomed() 
  g.attr("transform", d3.event.transform);//The zoom and panning is affecting my G element which is a child of SVG


function centerNode(source)

  t = d3.zoomTransform(zoomer.node());
  console.log(t);

  x =  t.x;
  y = source.x0;

  y = -y *t.k + viewerHeight / 2;

  g.transition()
   .duration(duration)
   .attr("transform", "translate(" + x + "," + y + ")scale(" + t.k + ")")
   .on("end", function() zoomer.call(zoom.transform, d3.zoomIdentity.translate(x,y).scale(t.k)));



根据 d3.js 页面上的 v4 示例,我使用矩形将缩放应用到

缩放行为应用于覆盖 SVG 的不可见矩形 元素;这确保它接收输入,并且指针 坐标不受缩放行为变换的影响。 Pan & Zoom Example

在中心节点函数中,我使用d3.zoomTransform(zoomer.node()); 来获取应用于页面的当前变换。 此函数的目的只是使可折叠树垂直居中而不是水平居中,因此我保持当前的 transform.x(此处为 t.x)相同。 我的 svg 中的坐标是翻转的,因此为什么 y= source.x0, source 是在我的可折叠树中单击了什么节点。 (“查看此线程顶部引用的示例以了解我要转换为版本 4 的内容)

我将转换应用到我的 G 元素,然后我想将这些更改提交给缩放转换,为此我使用 .on("end", function()) 否则它会在转换中出现奇怪的行为,通过这样做正在设置变换的当前状态。

zoomer.call(zoom.transform, d3.zoomIdentity.translate(x,y).scale(t.k))

上面的这一行正在应用 x 和 y 的平移和比例 - 等于当前状态 - 到身份矩阵必须获得 G 的新变换,然后我将其应用到 zoomer这是我之前称为zoom 的元素。

这对我来说就像一个魅力!

【讨论】:

我自己正在经历这个转换过程,发现这很有帮助。但我仍然不明白添加“rect”对象的目的。也许是因为我不明白什么是“指针坐标”,也不明白缩放变换会如何影响它们。 我遵循了那个示例,然后重构以删除“rect”。看不出有什么不妥。【参考方案2】:

调用transform.scaletransform.translate 会返回一个新的转换,并且不会修改任何内容。因此:

transform = transform.translate([x, y]).scale(k)

svg.call(zoomListener.transform, newTransform)

(此时zoomListener 是一个相当不准确的名称,但无论如何......)

kxy 可以从 source 派生,可能如您所展示的那样,但我不确定,因为我不知道 source 是什么。但对我来说,t.x*t.k 看起来很可疑,因为它将现有的变换 x 乘以它的比例。似乎会导致反馈循环。

如需详细了解 v4 中的缩放,请查看 this related *** post 或 this example by mbostock,演示对元素(在本例中为画布)的缩放变换和包括过渡的编程控制。

【讨论】:

source 是我在上面提到的示例中的树中事件的来源.. @Yourinium 对,但我不知道定义 source.x0source.y0 的术语。就像它们是纬度/经度对还是像素?我猜是像素。无论如何,我自己也在进行类似的转换,所以以后可能会有更多的见解...... @Yourinium 我发现在使用新的zoomTransform 对象时,转换的顺序很重要。具体来说,translate() 应该在scale() 之前,否则内部的翻译会乘以比例。我修改了答案以反映这一点。 很高兴知道。是的,source.x0 和 source.y0 来自 svg 坐标系,所以以像素为单位。 x0 相当于 y 坐标,y0 相当于 d3 平移的 x 坐标 另外,当我使用 d3.zoomTransform(node) 函数时,我得到的只是单位矩阵,我已经缩放和平移,然后我尝试了 d3.zoomTransform(zoom) d3.zoomTransform(zoom, svg)d3.zoomTransform(svg) in控制台,它总是`k:1 x;0 y:0`,我不确定如何使用该函数来获取当前转换。你对此有什么见解吗? @meetamit

以上是关于d3.js 在版本 4 中重写缩放示例的主要内容,如果未能解决你的问题,请参考以下文章

在 D3.js 中缩放或平移时限制域

Javascript / D3.js - 绘制大型数据集 - 提高 d3.js 绘制的 svg 图表中的缩放和平移速度

d3js中的缩放线

D3.JS 具有实时数据、平移和缩放的时间序列折线图

D3.js 缩放和平移可折叠树图

使用canvas和d3.js分层圆结构计算缩放和平移的方法