颠倒 d3.zoom 缩放和平移的顺序

2024-03-26

如果您单击本例中的红色按钮:

https://bl.ocks.org/interwebjill/fe782e6f195b17f6fe6798a24c390d90 https://bl.ocks.org/interwebjill/fe782e6f195b17f6fe6798a24c390d90

您可以看到图表进行了平移,使圆圈位于中心,然后放大到指定级别(重新单击按钮会缩小)。以这种方式平移然后缩放会在左侧留下一个我不希望有的间隙。我如何更改代码,以便图表首先缩放,然后平移到中心,这样图表中就不会出现这种间隙?

我尝试反转缩放的顺序并在缩放定义和 ZoomToExtent 函数中进行翻译,但效果没有什么不同。


问题的最终根源是 d3.interpolateZoom。该插值器的缩放插值速度比平移速度更快 - 尽管它们大多数都是同时转换的。该模式的实现是d3.interpolateZoom是基于此paper https://www.win.tue.nl/~vanwijk/zoompan.pdf.

因为缩放和平移两者的插值方式不同d3.interpolateZoom,当比例减小/增大的速度快于平移值时,图表的一侧会出现间隙。

d3.interpolateZoom当您在过渡上调用缩放时使用。

但是,如果您直接在转换上应用转换,请使用.attr(),d3 过渡将使用d3.interpolateString,它将在开始和结束字符串中搜索相应的数字并使用d3.interpolateNumber关于那些。这将对缩放和平移应用相同的插值。

使用这两种方法,我们可以比较 d3.interpolateZoom 和 d3.interpolateString 之间的差异。下面黑色矩形使用d3.interpolateString而橙色矩形使用d3.interpolateZoom。单击矩形开始过渡:

var svg = d3.select("body").append("svg")
   .attr("width", 500)
   .attr("height", 300);
   
var g1 = svg.append("g"), g2 = svg.append("g");

var zoom1 = d3.zoom().on("zoom", function() { 
   g1.attr("transform", d3.event.transform);
});

var zoom2 = d3.zoom().on("zoom", function() {
   g2.attr("transform", d3.event.transform);
});

g1.call(zoom1.transform, d3.zoomIdentity  
       .translate(150, 100)
       .scale(2));
       
g2.call(zoom2.transform, d3.zoomIdentity
       .translate(150,100)
       .scale(2));

g1.append("rect")
   .attr("x", 20)
   .attr("y", 20)
   .attr("width", 50)
   .attr("height", 50);
   
g2.append("rect")
  .attr("x", 22)
  .attr("y", 22)
  .attr("width", 46)
  .attr("height",46)
  .attr("fill","orange");
   
d3.selectAll("rect").on("click", function() {
                                                               
   g1.transition()
      .duration(6000)
      .attr("transform", d3.zoomIdentity)
      .on("end", function() {
				d3.select(this).call(zoom1.transform, d3.zoomIdentity);			  
			})
      
   g2.transition()
      .duration(6000)
      .call(zoom2.transform, d3.zoomIdentity)
      

});
<script type="text/javascript" src="https://d3js.org/d3.v5.js"></script>

在第一个矩形使用 .attr() 过渡变换的情况下,我们需要随后调用缩放以确保缩放具有当前变换,在本例中我们不需要,但如果您想在变换后使用缩放你需要这样做

比较这两个我们得到:

(Y 轴表示从开始属性到结束属性的转换中剩余的百分比)


您希望缩放和平移在转换时以相同的速率同时移动。如果我们使用补间函数,我们就可以做到这一点。与上面不同的是,我们不能只使用transition().attr("transform",newTransfrom)因为您也在绘制画布并更新轴。因此,我们需要创建自己的补间函数,该函数可以使用当前的变换和比例,将其应用于轴、画布和标记。

例如,不调用缩放(将使用 d3.interpolateZoom):

function zoomToExtent(d0, d1) {
  zoomRect.call(zoom).transition()
    .duration(1500)
    .call(zoom.transform, d3.zoomIdentity  
       .translate(-xSVG(d0), 0)
       .scale(width / (xSVG(d1) - xSVG(d0))));
  }

相反,我们可以使用补间函数来控制元素的变换并应用相同的插值器来缩放和平移:

function zoomToExtent(d0, d1) {
  //get transition start and end values:
  var startScale = d3.zoomTransform(zoomRect.node()).k;
  var startTranslate = d3.zoomTransform(zoomRect.node()).x;
  var endTranslate = -xSVG(d0);
  var endScale = width / (xSVG(d1) - xSVG(d0));

  zoomRect.call(zoom).transition()
    .duration(1500)
    .tween("transform", function() {
      var interpolateScale = d3.interpolateNumber(startScale,endScale);
      var interpolateTranslate = d3.interpolateNumber(startTranslate,endTranslate);

      return function(t) { 
          var t = d3.zoomIdentity.translate(interpolateTranslate(t),0).scale(interpolateScale(t));
          zoomed(t);
        }
      })
      .on("end", function() {    // update the zoom identity on end:
        d3.select(this).call(zoom.transform, d3.zoomIdentity  
       .translate(endTranslate, 0)
       .scale(endScale));
      })

  }

您可能会注意到我将变换值传递给缩放函数,因为没有 d3.event.transform ,我们需要修改缩放函数以使用传递的参数(如果可用),否则要依靠事件变换:

function zoomed(transform) {
   var t = transform || d3.event.transform;
   ...

总而言之,这可能看起来有些东西像这样 https://bl.ocks.org/Andrew-Reid/0d9a717117b4224b6abd3122717985a7.


对于两种过渡方法之间的另一个比较,我创建了一个可以在两个缩放标识之间切换的网格比较:

var svg = d3.select("body").append("svg")
   .attr("width", 510)
   .attr("height", 310);
   
var g1 = svg.append("g");
var g2 = svg.append("g");
   
var rectangles1 = g1.selectAll()
  .data(d3.range(750))
  .enter()
  .append("rect")
  .attr("x", function(d) { return d%25*20; })
  .attr("y", function(d) { return Math.floor(d/25)*20; })
  .attr("width", 20)
  .attr("height", 20)
  .attr("fill","#ccc")
  .attr("stroke","white")
  .attr("stroke-width", 2);
  
var rectangles2 = g2.selectAll()
  .data(d3.range(750))
  .enter()
  .append("rect")
  .attr("x", function(d) { return d%25*20; })
  .attr("y", function(d) { return Math.floor(d/25)*20; })
  .attr("width", 20)
  .attr("height", 20)
  .attr("fill","none")
  .attr("stroke","#444")
  .attr("stroke-width", 1);
  
var startZoom = d3.zoomIdentity
  .translate(-250,-200)
  .scale(4);

var endZoom = d3.zoomIdentity
  .translate(-100,-100)
  .scale(5);
  
var zoom1 = d3.zoom().on("zoom", function() { g1.attr("transform", d3.event.transform); });
var zoom2 = d3.zoom().on("zoom", function() { g2.attr("transform", d3.event.transform); });

g1.call(zoom1.transform, startZoom);
g2.call(zoom2.transform, startZoom);

var toggle = true;

svg.on("click", function() {
  toggle = !toggle;
  g1.transition()
    .duration(5000)
    .call(zoom1.transform, toggle ? startZoom: endZoom)
    
  g2.transition()
    .duration(5000)
    .attr("transform", toggle ? startZoom: endZoom)
    .on("end", function() {
      d3.select(this).call(zoom2.transform,  toggle ? startZoom: endZoom);
    })
    
    
})
rect {
  opacity: 0.5;
}
<script type="text/javascript" src="https://d3js.org/d3.v5.js"></script>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

颠倒 d3.zoom 缩放和平移的顺序 的相关文章

  • 将 D3 svg 保存为高质量图像

    有没有办法将 D3 SVG 图像保存为高质量图像 如果是的话请解释一下 截至目前 我正在使用以下代码将 svg 保存为图像 但我得到的图像质量不高 var canvas1 document createElement canvas canv
  • d3 单击时聚焦于节点

    我正在尝试实现一种力布局 其中单击节点将能够专注于节点周围的区域 我看过一些例子 但我收到一个错误 上面写着link bounds is not defined 我认为边界没有为力布局定义 并且适用于我从中获取聚焦功能的示例http bl
  • D3.js - 如何迭代数据集中的子数组

    我试图让 d3 迭代数据中的子数组并生成多个饼图 这是完整的代码 来自https gist github com mbostock 1305111 https gist github com mbostock 1305111 and htt
  • R/d3heatmap/shiny - 有没有办法在 d3 工具提示中嵌入图像?

    我想在滚动单元格时在 d3 工具提示中嵌入图像 而不是默认的行 列 值数据 library shiny library d3heatmap ui lt shinyUI fluidPage titlePanel Old Faithful Ge
  • 数据与线的日期和时间转换

    我使用 D3 V5 创建了此图表 另外 我已在小提琴上附加了示例数据 您可以点击此处查看 https plnkr co edit pINxcS9yt9AuJmSk02Fs p preview 我已经包括了tick函数代码块 它在向左滑动的路
  • d3.forcesimulation() 链接距离

    我在堆栈上查看了不同的链接距离 似乎为了改变链接距离 您需要实现一个函数 然后传递它来动态分配链接距离 如下所示 function linkDistance d return d distance 然后我认为我可以传递给 svg 但返回函数
  • d3.js:在树布局中展开多个路径

    My JSON contains same node names in different paths I would like to be able to open all children with the same name or h
  • 我可以补间 D3 弧的结束角度,但不能补间起始角度。我究竟做错了什么?

    我只是在玩这个演示并自己重新创建它 http bl ocks org mbostock 5100636 http bl ocks org mbostock 5100636 我可以定义一个新的 endAngle 并且它会很好地制作动画 但现在
  • d3 地理投影从正交到 X 的过渡

    我正在开发一个教育地图项目 其中显示不同的地图投影 我想在选择不同投影之间实现变形过渡 我找到了一个很好的例子来实现它 并且我没有遇到太多的麻烦来重新创建它 不幸的是 我还需要裁剪投影的功能 这与目标状态完美配合 但在改变投影时则不然 当选
  • D3.js 中的点图

    我有兴趣创建一个Dot plot 每个数据值都有连续的点 但到目前为止我所管理的是为每个值创建一个点 更清楚地说 假设对于 array1 我希望第一个值创建 5 个圆圈 第二个值创建 4 个圆圈 依此类推 array1 5 4 2 0 3
  • 增加浏览器缩放时 mediaelement.js 音量控制混乱

    媒体元素2 12 0 这种情况仅发生在 FF 和 Chrome 中 而不会发生在 IE 或 Opera 中 导航到具有媒体元素播放器的网站内容后 甚至导航到媒体元素首页http mediaelementjs com http mediael
  • d3.js:非线性图轴

    我正在尝试在轴上添加自定义比例 如下所示 这个想法是 一个刻度总是比前一个刻度大 2 倍 我的理解是 这是一个定制秤 我做了一些研究 但找不到类似的东西 所以我想我的问题实际上是两个问题 这个尺度是数学世界的 标准 吗 这是否可以使用来实现
  • 使用 d3 进行多级/分组轴标签

    我想知道是否有一种简单的方法可以在 d3 中添加多级 分层 分组轴标签 例如 如果我有一个折线图 其中 x 轴的月份名称跨越多年 那么我还希望将年份作为月份名称下方的标签 因此它看起来像这样 Oct Nov Dec Jan Feb Mar
  • D3 旭日弧尺寸

    我正在尝试根据以下示例创建 D3 旭日图 https bl ocks org maybelinot 5552606564ef37b5de7e47ed2b7dc099 https bl ocks org maybelinot 55526065
  • d3.js 更新视觉效果

    我有一个与 d3 js 放在一起的树形图 我通过 getJSON 填充数据 效果很好 但是 我在 setInterval 方法中具有此功能 并且它似乎并没有刷新自身 var treemap d3 layout treemap padding
  • 将文本放置在矩形的中心

    在下面的代码中 文本没有放置在矩形的中心 我使用的是 attr dx x bandwidth 2 attr dy y bandwidth 2 有没有办法将文本中心放置在矩形中 而不是反复试验 目前它看起来像这样 朝底部和朝右 以下是我的代码
  • D3.js - 具有多个环的圆环图

    以下示例显示了 D3 js 中的圆环图 是否可以向图表添加多个圆环 var dataset apples 53245 28479 19697 24037 40245 var width 460 height 300 radius Math
  • 需要帮助绘制多元线之间的区域 - 而不是从轴到线

    我是 d3 js 的新手 我正在努力填充多元百分位数图中线条之间的区域 我不希望在最底线下方或最顶线上方填充任何区域 第一列始终位于图表的底部 第 5 个百分位 最后一列将始终位于图表的顶部 第 95 个百分位 我需要每条线之间单独的区域段
  • 使圆圈与 d3.js 上的多线匹配相同的颜色过滤?

    我有一个多线图 当按每种水果过滤时会更新 每条线条颜色对应不同的销售年份 在 的帮助下Shashank https stackoverflow com users 5569282 shashank 每个数据点线上的圆圈已添加到组中 而不是直
  • 如何根据形状字段值将两个不同的形状添加到 D3 力向图?

    我是D3的新手 我正在使用力定向图 我想在节点的位置添加两种不同类型的形状 我的 json 如下 nodes name 00 00 00 00 00 00 00 01 group 0 shape 1 name 00 00 00 00 00

随机推荐