d3转换有哪些属性变化?

时间:2017-11-16 21:55:03

标签: javascript html animation d3.js svg

我想了解d3到底有什么转变。

例如

var bars = svg.selectAll(null)
  .data(my_values)
  .enter()
  .append("rect") // statement before transition
  .attr("x", 10)  // statement before transition
  .transition()   // transition
  .delay(200)
  .duration(1500)
  .attr("height", 10) // statement after transition
  .transition()   // another transition
  .delay(200)
  .duration(1500);
  1. 过渡是否会影响过渡前的任何陈述,或仅在过渡后影响过渡效果语句

  2. 多个过渡如何运作?

1 个答案:

答案 0 :(得分:8)

你的第二个问题......

  
      
  1. 多个过渡如何运作?
  2.   

回答很简单。这里,API很明确:

  

transition.transition()

     

返回与此转换相同的所选元素的新转换,计划在此转换结束时启动。

因此,新的转换将在前一个转换完成时开始,依此类推。让我们看看:



var rect = d3.select("svg").append("rect")
  .attr("width", 100)
  .attr("height", 0)
  .style("fill", "black")
  .transition()
  .duration(1000)
  .attr("height", 100)
  .transition()
  .duration(1000)
  .style("fill", "teal")

<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
&#13;
&#13;
&#13;

有趣的问题

然而,这里有趣的问题是你的第一个:

  
      
  1. 转换是在转换之前影响任何语句还是在转换后仅转换效果语句?
  2.   

嗯,这也很基本:transition()方法在起始值和目标值之间创建转换。您必须在转换(起始值)之前和转换之后(目标值)设置属性。

问题是先前未设置的属性将具有null值。

让我们看一下:如果没有指定矩形的height,它就是null

&#13;
&#13;
var rect = d3.select("svg").append("rect");

console.log(rect.attr("height"))
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
&#13;
&#13;
&#13;

因此,如果您未在转换前设置它,则没有关于高度的平滑过渡:

&#13;
&#13;
var rect = d3.select("svg").append("rect")
  .attr("width", 100)
  .transition()
  .duration(1000)
  .attr("height", 100);
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
&#13;
&#13;
&#13;

这里有一个有趣的观点:我写了一个答案(现已删除,用户>&gt; 10k可以看到它),解释说插补器无法从null插值到给定值。但是,可以插值:

&#13;
&#13;
var interpolator = d3.interpolateNumber(null, 100);
d3.range(0,1.1,.1).forEach(function(d){
	console.log(interpolator(d))
});
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
&#13;
&#13;
&#13;

所以,这里发生的事情有点复杂。使用interpolateNumber,我们可以从null插值到给定值。看看这个没有设置height的演示:

&#13;
&#13;
var rect = d3.select("svg").append("rect")
  .attr("width", 100)
  .transition()
  .duration(1000)
  .attrTween("height", function() {
    return d3.interpolateNumber(d3.select(this).attr("height"), 100);
  });
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
&#13;
&#13;
&#13;

为什么默认transition.attr()在转换前未设置属性时无法正常工作?

经过一些调查后,在我看来transition()正在将数字目标值转换为字符串(如100"100")。这很奇怪,因为API explicitly says ......

  

...基于目标值的类型选择插值器,使用以下算法:

     
      
  1. 如果值是数字,请使用interpolateNumber
  2.   
  3. 如果值是颜色或可强制颜色的字符串,请使用interpolateRgb
  4.   
  5. 使用interpolateString
  6.   

这是source code,请看最后一行:

export default function(name, value) {
    var fullname = namespace(name),
        i = fullname === "transform" ? interpolateTransform : interpolate;
    return this.attrTween(name, typeof value === "function" 
        ? (fullname.local ? attrFunctionNS : attrFunction)(fullname, i, tweenValue(this, "attr." + name, value)) 
        : value == null ? (fullname.local ? attrRemoveNS : attrRemove)(fullname) 
        : (fullname.local ? attrConstantNS : attrConstant)(fullname, i, value + ""));
        //converting to string here ------------------------------------------^
}

正如我们所看到的,它将值强制转换为字符串。因此,转换无效,因为它将使用interpolateString代替interpolateNumber

&#13;
&#13;
var interpolator = d3.interpolateString(null, "100");
d3.range(0,1.1,.1).forEach(function(d){
	console.log(interpolator(d))
});
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
&#13;
&#13;
&#13;

结论

transition()创建从起始值到目标值的转换。如果未设置起始值,则默认为null。但是,由于transition()使用interpolateString,插值将无法正常工作。

2017年11月18日更新

根据Mike Bostock(D3创建者)的说法,源代码是正确的(因此,文档是错误的)。正如他在GitHub issue中所说的那样:

  

interpolateString(或interpolateRgb)是正确的行为。永远不应该将interpolateNumber用于属性。

解释是,"100px""1.3em"等值不适用于interpolateNumber。因此,请不要依赖null起始值:始终在transition()之前和之后设置属性。

感谢@altocumulus评论GitHub问题。