我想了解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);
过渡是否会影响过渡前的任何陈述,或仅在过渡后影响过渡效果语句
多个过渡如何运作?
答案 0 :(得分:8)
你的第二个问题......
- 多个过渡如何运作?
醇>
回答很简单。这里,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;
然而,这里有趣的问题是你的第一个:
- 转换是在转换之前影响任何语句还是在转换后仅转换效果语句?
醇>
嗯,这也很基本:transition()
方法在起始值和目标值之间创建转换。您必须在转换(起始值)之前和转换之后(目标值)设置属性。
问题是先前未设置的属性将具有null
值。
让我们看一下:如果没有指定矩形的height
,它就是null
:
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;
因此,如果您未在转换前设置它,则没有关于高度的平滑过渡:
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;
这里有一个有趣的观点:我写了一个答案(现已删除,用户>&gt; 10k可以看到它),解释说插补器无法从null
插值到给定值。但是,可以插值:
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;
所以,这里发生的事情有点复杂。使用interpolateNumber
,我们可以从null
插值到给定值。看看这个没有设置height
的演示:
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;
为什么默认transition.attr()
在转换前未设置属性时无法正常工作?
经过一些调查后,在我看来transition()
正在将数字目标值转换为字符串(如100
到"100"
)。这很奇怪,因为API explicitly says ......
...基于目标值的类型选择插值器,使用以下算法:
- 如果值是数字,请使用
interpolateNumber
。- 如果值是颜色或可强制颜色的字符串,请使用
interpolateRgb
。- 使用
醇>interpolateString
。
这是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
:
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;
transition()
创建从起始值到目标值的转换。如果未设置起始值,则默认为null
。但是,由于transition()
使用interpolateString
,插值将无法正常工作。
根据Mike Bostock(D3创建者)的说法,源代码是正确的(因此,文档是错误的)。正如他在GitHub issue中所说的那样:
interpolateString
(或interpolateRgb
)是正确的行为。永远不应该将interpolateNumber
用于属性。
解释是,"100px"
或"1.3em"
等值不适用于interpolateNumber
。因此,请不要依赖null
起始值:始终在transition()
之前和之后设置属性。
感谢@altocumulus评论GitHub问题。