【问题标题】:Transition circle radius in d3 to cancel scaling transition--works but timing is offd3 中的过渡圆半径以取消缩放过渡--有效但计时已关闭
【发布时间】:2014-09-28 22:40:20
【问题描述】:

这是一些示例代码和其中的一个小技巧:

var w = 400;
var h = 400;
var r = 20;
var factor = 5;

var svg = d3.select("body").append("svg")
    .attr("width", w)
    .attr("height", h)
    .append("g")
    .attr("transform", "translate(" + w/2 + "," + h/2 + ")");

svg.append("circle")
    .attr("cx", 0)
    .attr("cy", 0)
    .attr("r", r)
    .style("fill", "black");

svg.append("circle")
    .attr("cx", 150)
    .attr("cy", 150)
    .attr("r", r)
    .style("fill", "red");

svg.selectAll("circle")
    .transition()
    .duration(2000)
    .attr("transform", "scale(" + 1/factor +")")
    .attr("r", r*factor);

http://jsfiddle.net/o1wzfas7/2/

在示例中,我将两个圆缩小了 5 倍(这也缩放了它们的位置,从而使它们彼此“更接近”),同时将圆的半径放大了 5 倍。想法是它们看起来会在不改变大小的情况下彼此靠近(好像我正在改变它们的“cx”和“cy”属性),但由于某种原因,比例转换和半径转换似乎以不同的速率进行,因此您会看到圆圈变大,然后恢复到初始大小。

有谁知道我将如何使用比例和半径过渡来做到这一点,但是让两者相互抵消,这样圆圈的大小就不会发生变化?

【问题讨论】:

  • 你有什么理由不能做像this这样的事情吗?
  • 如果你想让它们靠近而不改变大小,为什么不直接这样做呢?
  • 合理的问题,@royhowie。我有一个散点图,我希望能够在限制范围内进行缩放和平移。目前在 d3 API 中似乎并没有很好地处理这个问题(缩放限制是 - 平移限制不是)。在尝试实施平移限制之前,我 只是简单地更改了 cx 和 cy,生活还不错。现在我正在做类似于 Mike Bostock 在这里所做的事情:bl.ocks.org/mbostock/4987520 总而言之,我现在要处理缩放而不是 cx 和 cy 变化。
  • @AmeliaBR royhowie 提出了类似的问题——请参阅我的回复。
  • 感谢@ErikMadsen 的解释。在其中一种情况下,演示问题的简化工作示例(当然非常感谢)最终使基本目标变得微不足道。

标签: javascript svg d3.js transition


【解决方案1】:

首先,解释一下发生了什么:

问题在于,您所做的更改以相乘方式抵消,但转换以相加方式进行。

因此,对于您的简单示例,半径 (r) 从 20 开始,比例 (s) 从 1 开始(隐式)并且您正在转换 5 倍,圆的有效半径为 r*s :

过渡开始时:

  • r =20
  • s =1
  • r*s =20

过渡结束时:

  • r =4
  • s =5
  • r*s =20

现在,您在脑海中的想法是,因素应该从 1 转变为 5,但这不是将要发生的事情。默认的转换函数看不到你的因子,他们只是看到半径从 20 转换到 4,比例从 1 转换到 5。

因此,在过渡的中点,每个属性将处于其开始值和结束值的中点(平均值):

  • r = (20+4)/2 = 12
  • s = (1+5)/2 = 3
  • r*s = 36

为了做你想做的事,你必须创建一个自定义补间,它直接转换因子,然后从那里计算半径和比例:

svg.selectAll("circle")
    .transition()
    .duration(2000)
    .tween("factor", function(d,i){
        /* create an interpolator for your factor */
        var f = d3.interpolateNumber(1,factor);

        /* store the selected element in a variable for easy modification */
        var c = d3.select(this);

        /* return the function which will do the updates at each tick */
        return function(t) {
           var f_t = f(t);
           c.attr("transform", "scale(" + 1/f_t + ")" );
           c.attr("r", r*f_t );
        };
     });

请注意,在您的实际应用程序中,您需要将因子转换的“开始”值存储在全局变量或每个数据对象中,因为当您转换到不同的缩放因子时,它不会自动为 1 .

var w = 400;
var h = 400;
var r = 20;
var factor = 5;

var svg = d3.select("body").append("svg")
    .attr("width", w)
    .attr("height", h)
    .append("g")
    .attr("transform", "translate(" + w/2 + "," + h/2 + ")");

svg.append("circle")
    .attr("cx", 0)
    .attr("cy", 0)
    .attr("r", r)
    .style("fill", "black");

svg.append("circle")
    .attr("cx", 150)
    .attr("cy", 150)
    .attr("r", r)
    .style("fill", "red");


svg.selectAll("circle")
    .transition()
    .duration(2000)
    .tween("factor", function(d,i){
        /* create an interpolator for your factor */
        var f = d3.interpolateNumber(1,factor);

        /* store the selected element in a variable for easy modification */
        var c = d3.select(this);

        /* return the function which will do the updates at each tick */
        return function(t) {
           var f_t = f(t);
           c.attr("transform", "scale(" + 1/f_t + ")" );
           c.attr("r", r*f_t );
        };
     });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

【讨论】:

  • 谢谢!我得花点功夫才能在我的真实代码中按照我想要的方式工作,但这是有道理的,正是我需要的答案。
  • 我假设在“真实”代码中,缩放变换发生在父 <g> 元素上,因此您不想在一个补间函数中完成所有操作。您仍然可以使用在自定义补间中转换缩放因子,然后计算属性值的想法,但您可以使用.attrTween 方法,因为每个自定义补间函数只会影响一个属性。
  • 谢谢,我已经搞定了。我实际上是单独缩放〜2000个圆圈,尽管我没有理由不能重写一些东西,以便圆圈都是一个组的成员,我认为我应该这样做。直觉上我怀疑扩展一个组在计算上会更轻,但是你是否碰巧知道这是否真的是这样(至少在任何显着程度上)?
  • 我没有任何关于单独转换元素与转换组的渲染性能的经验数据。我认为该小组具有优势,但可能并不重要。但是,我可以肯定地说,您将节省 d3 转换函数进行的 setAttribute 调用(以及转换命令的结果解析)的数量,如果您有 2000 个圆圈,这可能会有所不同每次更新都更新。
  • 是的,呼叫越少越好。但是,我想我至少要选择所有圆来更新半径,因为据我所知,圆属性 r 不是可以作为一个组继承的东西。 (我还是 JavaScript 和 d3 的新手,所以我想错了!)
猜你喜欢
  • 1970-01-01
  • 2021-05-28
  • 2013-11-22
  • 1970-01-01
  • 1970-01-01
  • 2015-11-01
  • 1970-01-01
  • 2013-07-10
  • 1970-01-01
相关资源
最近更新 更多