我试图了解什么在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);
最佳答案
你的第二个问题...
- How does multiple transition work?
答案很简单。在这里,API很清楚:
transition.transition()
Returns a new transition on the same selected elements as this transition, scheduled to start when this transition ends.
因此,新过渡将在上一个过渡完成时开始,依此类推。让我们来看看它:
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>
有趣的问题
但是,这里有趣的问题是您的第一个问题:
- Does the transition effect any statement before the transition or does the transition effect only statement after the transition?
嗯,这也很基础:
transition()
方法在起始值和目标值之间创建过渡。您必须在过渡之前(起始值)和过渡之后(目标值)设置属性。问题在于先前未设置的属性将具有
null
值。让我们看一下:在不指定矩形的
height
的情况下,它是null
:var rect = d3.select("svg").append("rect");
console.log(rect.attr("height"))
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
因此,如果未在过渡前设置高度,则不会有平滑的过渡:
var rect = d3.select("svg").append("rect")
.attr("width", 100)
.transition()
.duration(1000)
.attr("height", 100);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
有趣的是:我写了一个答案(现已删除,> 10k的用户可以看到),解释说插值器无法从
null
插值到给定值。但是,可以进行插值:var interpolator = d3.interpolateNumber(null, 100);
d3.range(0,1.1,.1).forEach(function(d){
console.log(interpolator(d))
});
<script src="https://d3js.org/d3.v4.min.js"></script>
因此,这里发生的事情更加复杂。使用
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);
});
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
当您在转换前未设置属性时,为什么默认的
transition.attr()
不起作用?经过一番调查,在我看来
transition()
正在将数字目标值转换为字符串(例如100
到"100"
)。这很奇怪,因为API explicitly says表示...... an interpolator is chosen based on the type of the target value, using the following algorithm:
- If value is a number, use
interpolateNumber
.- If value is a color or a string coercible to a color, use
interpolateRgb
.- Use
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))
});
<script src="https://d3js.org/d3.v4.min.js"></script>
结论
transition()
创建从起始值到目标值的过渡。如果未设置起始值,则默认为null
。但是,由于transition()
使用interpolateString
,因此插值将无法正常工作。2017年11月11日更新
根据Mike Bostock(D3创建者)的说法,源代码是正确的(因此,文档是错误的)。正如他在GitHub issue中所说:
interpolateString
(orinterpolateRgb
) is the correct behavior here.interpolateNumber
should never be used for attributes.
原因是
"100px"
或"1.3em"
之类的值不适用于interpolateNumber
。因此,再次,不要依赖null
的起始值:始终在transition()
之前和之后设置属性。感谢@altocumulus对GitHub问题发表评论。
关于javascript - d3转换会改变哪些属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47339762/