对 d3.interpolateObject 的困惑
Confusion about d3.interpolateObject
我刚刚调查 D3 Interpolate Object function,我注意到一些奇怪的行为。但是,我对 D3 不是很熟悉,所以可能我只是误解了一些东西。给定以下数据和插值函数:
var a = {"Country": "Ireland", "Year": 2010, "Data": 10};
var b = {"Country": "Ireland", "Year": 2015, "Data": 50};
var iFunc = d3.interpolateObject(a, b);
以下结果符合预期:
console.log(iFunc(0.2)) // Returns: { Country: "Ireland", Year: 2011, Data: 18 }
console.log(iFunc(0.4)) // Returns: { Country: "Ireland", Year: 2012, Data: 26 }
但是,当两个函数调用都包含在同一个控制台日志中时,如下所示:
console.log(iFunc(0.2), iFunc(0.4))
输出只是第二个对象两次:
{ Country: "Ireland", Year: 2012, Data: 26 } { Country: "Ireland", Year: 2012, Data: 26 }
并且,当函数调用像这样放在数组中时:
console.log([iFunc(0.2), iFunc(0.4)])
之前的输出乘以二:
[{ Country: "Ireland", Year: 2014, Data: 42 }, { Country: "Ireland", Year: 2014, Data: 42 }]
这是怎么回事?
我正在研究这个的原因是我想使用类似的东西创建一系列中间对象:
var iVals = d3.range(0, 1, 0.2).map( iFunc );
如果有人能告诉我如何实现这一点,我将不胜感激!
这是一个有趣的问题。解释可以在自己的documentation:
中找到
Note: no defensive copy of the template object is created; modifications of the returned object may adversely affect subsequent evaluation of the interpolator. No copy is made for performance reasons; interpolators are often part of the inner loop of animated transitions. (emphasis mine)
如您所见,如果您使用相同的插值器,您会得到您描述的奇怪结果(打开浏览器的控制台,不要使用代码段的控制台):
var a = {
"Country": "Ireland",
"Year": 2010,
"Data": 10
};
var b = {
"Country": "Ireland",
"Year": 2015,
"Data": 50
};
var iFunc = d3.interpolateObject(a, b);
var iVals = d3.range(0, 1, 0.2).map(iFunc);
console.log(iVals)
<script src="https://d3js.org/d3.v5.min.js"></script>
因此,最简单的解决方案是在 map()
:
中定义插值器函数
var iVals = d3.range(0, 1, 0.2).map(function(d) {
return d3.interpolateObject(a, b)(d)
});
这是演示:
var a = {
"Country": "Ireland",
"Year": 2010,
"Data": 10
};
var b = {
"Country": "Ireland",
"Year": 2015,
"Data": 50
};
var iVals = d3.range(0, 1, 0.2).map(function(d) {
return d3.interpolateObject(a, b)(d)
});
console.log(iVals)
<script src="https://d3js.org/d3.v5.min.js"></script>
或者,创建一个 returns 插值器的函数:
var iFunc = function(d) {
return d3.interpolateObject(a, b)(d)
};
var iVals = d3.range(0, 1, 0.2).map(iFunc);
对应的demo如下:
var a = {
"Country": "Ireland",
"Year": 2010,
"Data": 10
};
var b = {
"Country": "Ireland",
"Year": 2015,
"Data": 50
};
var iFunc = function(d) {
return d3.interpolateObject(a, b)(d)
};
var iVals = d3.range(0, 1, 0.2).map(iFunc);
console.log(iVals)
<script src="https://d3js.org/d3.v5.min.js"></script>
PS:与你的问题无关,但d3.range()
中的"stop"值不包含在内。所以,如果要获取对象b
中的值,应该是:
d3.range(0, 1.2, 0.2)
这里是:
var a = {
"Country": "Ireland",
"Year": 2010,
"Data": 10
};
var b = {
"Country": "Ireland",
"Year": 2015,
"Data": 50
};
var iVals = d3.range(0, 1.2, 0.2).map(function(d) {
return d3.interpolateObject(a, b)(d)
});
console.log(iVals)
<script src="https://d3js.org/d3.v5.min.js"></script>
我刚刚调查 D3 Interpolate Object function,我注意到一些奇怪的行为。但是,我对 D3 不是很熟悉,所以可能我只是误解了一些东西。给定以下数据和插值函数:
var a = {"Country": "Ireland", "Year": 2010, "Data": 10};
var b = {"Country": "Ireland", "Year": 2015, "Data": 50};
var iFunc = d3.interpolateObject(a, b);
以下结果符合预期:
console.log(iFunc(0.2)) // Returns: { Country: "Ireland", Year: 2011, Data: 18 }
console.log(iFunc(0.4)) // Returns: { Country: "Ireland", Year: 2012, Data: 26 }
但是,当两个函数调用都包含在同一个控制台日志中时,如下所示:
console.log(iFunc(0.2), iFunc(0.4))
输出只是第二个对象两次:
{ Country: "Ireland", Year: 2012, Data: 26 } { Country: "Ireland", Year: 2012, Data: 26 }
并且,当函数调用像这样放在数组中时:
console.log([iFunc(0.2), iFunc(0.4)])
之前的输出乘以二:
[{ Country: "Ireland", Year: 2014, Data: 42 }, { Country: "Ireland", Year: 2014, Data: 42 }]
这是怎么回事?
我正在研究这个的原因是我想使用类似的东西创建一系列中间对象:
var iVals = d3.range(0, 1, 0.2).map( iFunc );
如果有人能告诉我如何实现这一点,我将不胜感激!
这是一个有趣的问题。解释可以在自己的documentation:
中找到Note: no defensive copy of the template object is created; modifications of the returned object may adversely affect subsequent evaluation of the interpolator. No copy is made for performance reasons; interpolators are often part of the inner loop of animated transitions. (emphasis mine)
如您所见,如果您使用相同的插值器,您会得到您描述的奇怪结果(打开浏览器的控制台,不要使用代码段的控制台):
var a = {
"Country": "Ireland",
"Year": 2010,
"Data": 10
};
var b = {
"Country": "Ireland",
"Year": 2015,
"Data": 50
};
var iFunc = d3.interpolateObject(a, b);
var iVals = d3.range(0, 1, 0.2).map(iFunc);
console.log(iVals)
<script src="https://d3js.org/d3.v5.min.js"></script>
因此,最简单的解决方案是在 map()
:
var iVals = d3.range(0, 1, 0.2).map(function(d) {
return d3.interpolateObject(a, b)(d)
});
这是演示:
var a = {
"Country": "Ireland",
"Year": 2010,
"Data": 10
};
var b = {
"Country": "Ireland",
"Year": 2015,
"Data": 50
};
var iVals = d3.range(0, 1, 0.2).map(function(d) {
return d3.interpolateObject(a, b)(d)
});
console.log(iVals)
<script src="https://d3js.org/d3.v5.min.js"></script>
或者,创建一个 returns 插值器的函数:
var iFunc = function(d) {
return d3.interpolateObject(a, b)(d)
};
var iVals = d3.range(0, 1, 0.2).map(iFunc);
对应的demo如下:
var a = {
"Country": "Ireland",
"Year": 2010,
"Data": 10
};
var b = {
"Country": "Ireland",
"Year": 2015,
"Data": 50
};
var iFunc = function(d) {
return d3.interpolateObject(a, b)(d)
};
var iVals = d3.range(0, 1, 0.2).map(iFunc);
console.log(iVals)
<script src="https://d3js.org/d3.v5.min.js"></script>
PS:与你的问题无关,但d3.range()
中的"stop"值不包含在内。所以,如果要获取对象b
中的值,应该是:
d3.range(0, 1.2, 0.2)
这里是:
var a = {
"Country": "Ireland",
"Year": 2010,
"Data": 10
};
var b = {
"Country": "Ireland",
"Year": 2015,
"Data": 50
};
var iVals = d3.range(0, 1.2, 0.2).map(function(d) {
return d3.interpolateObject(a, b)(d)
});
console.log(iVals)
<script src="https://d3js.org/d3.v5.min.js"></script>