在 d3js styleTween 中使用 CSS calc 时发生意外转换
Unexpected transition when using CSS calc in d3js styleTween
我想使用 CSS calc 计算 div 左边 属性 的开始 and/or 结束值,我想通过使用d3js 风格吐温。但是在开始向正确的终点过渡之前,div 向相反的方向跳跃。
我使用 Chromium 版本 73.0.3683.75 和 Firefox 60.7.0esr(64 位)测试了代码。这两者都会产生相同的意外行为。
使用 this.style.left 作为 d3.interpolate 中的第一个参数不会改变结果。
我在 d3js styleTween 文档中没有找到警告不要使用 calc 的注释,它在过渡结束时有效。
我希望先计算计算值,然后将结果传递给插值函数,这样就可以解决问题。但我不确定这是否可能。
<!DOCTYPE html>
<html>
<head>
<title>Odd interpolation with CSS calc and d3 styleTween</title>
<style>
html {height: 100%;}
body {height: 100%; margin:0; }
div.button {
position: absolute;
left: 20%;
width: 3rem;
height: 100%;
background-color: #0af;
}
</style>
</head>
<body>
<div class="button" id="menu_toggle"></div>
</body>
<script src="https://d3js.org/d3.v4.min.js" />
<script>
menu = function()
{
var div = d3.select('div.button');
var is_left = true;
function toggle_menu()
{
var left = "20%"
var right = "calc(80% - 3rem)"
if (is_left)
{
is_left = false;
div.transition().duration(2000)
.styleTween('left', function() { return d3.interpolate(left, right); });
}
else
{
is_left = true;
div.transition().duration(2000)
.styleTween('left', function() { return d3.interpolate(right, left); });
}
}
return {toggle_menu:toggle_menu}
}()
d3.select('#menu_toggle').on("click", menu.toggle_menu)
</script>
</html>
我希望在 20% 和 80%-3rem 这两个位置之间平稳过渡。
相反,当 div 从左侧开始时,它先向左跳 3rem,然后再向右移动。同样,如果div在右边,它先向右跳3rem,然后再向左移动。
问题非常简单:您正在插入 字符串 ,而不是它们的评估值。
当您在 CSS...
中执行此操作时
calc(80% - 3rem)
...它将被评估为一个像素值。到目前为止,一切都很好。但是,D3 插值器实际上是(双关语)从 "20%"
插值到 "calc(80% - 3rem)"
。当然,插值器不知道如何处理这个,它实际上是从 "calc(20% - 3rem)"
插值到 "calc(80% - 3rem)"
.
让我们看看:
const interpolator = d3.interpolate("20%", "calc(80% - 3rem)");
d3.range(0, 1.1, 0.1).forEach(d => {
console.log(interpolator(d))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
最简单的解决方案是评估 calc()
的结果并在插值器中使用该值。有几种方法可以做到这一点,比如使用 this library.
因此,假设在评估之后我们有一些值,例如 150px
和 430px
。现在插值很容易:
const interpolator = d3.interpolate("150px", "430px");
d3.range(0, 1.1, 0.1).forEach(d => {
console.log(interpolator(d))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
由于 d3s 字符串插值使用第二个输入(生成的字符串)作为模板,并将它找到的任何数字与第一个输入的对应数字(按索引匹配)进行插值,因此可以避免评估 css 通过对两个值进行插值来手动计算:
calc(20% - 0rem)
我想使用 CSS calc 计算 div 左边 属性 的开始 and/or 结束值,我想通过使用d3js 风格吐温。但是在开始向正确的终点过渡之前,div 向相反的方向跳跃。
我使用 Chromium 版本 73.0.3683.75 和 Firefox 60.7.0esr(64 位)测试了代码。这两者都会产生相同的意外行为。
使用 this.style.left 作为 d3.interpolate 中的第一个参数不会改变结果。
我在 d3js styleTween 文档中没有找到警告不要使用 calc 的注释,它在过渡结束时有效。
我希望先计算计算值,然后将结果传递给插值函数,这样就可以解决问题。但我不确定这是否可能。
<!DOCTYPE html>
<html>
<head>
<title>Odd interpolation with CSS calc and d3 styleTween</title>
<style>
html {height: 100%;}
body {height: 100%; margin:0; }
div.button {
position: absolute;
left: 20%;
width: 3rem;
height: 100%;
background-color: #0af;
}
</style>
</head>
<body>
<div class="button" id="menu_toggle"></div>
</body>
<script src="https://d3js.org/d3.v4.min.js" />
<script>
menu = function()
{
var div = d3.select('div.button');
var is_left = true;
function toggle_menu()
{
var left = "20%"
var right = "calc(80% - 3rem)"
if (is_left)
{
is_left = false;
div.transition().duration(2000)
.styleTween('left', function() { return d3.interpolate(left, right); });
}
else
{
is_left = true;
div.transition().duration(2000)
.styleTween('left', function() { return d3.interpolate(right, left); });
}
}
return {toggle_menu:toggle_menu}
}()
d3.select('#menu_toggle').on("click", menu.toggle_menu)
</script>
</html>
我希望在 20% 和 80%-3rem 这两个位置之间平稳过渡。
相反,当 div 从左侧开始时,它先向左跳 3rem,然后再向右移动。同样,如果div在右边,它先向右跳3rem,然后再向左移动。
问题非常简单:您正在插入 字符串 ,而不是它们的评估值。
当您在 CSS...
中执行此操作时calc(80% - 3rem)
...它将被评估为一个像素值。到目前为止,一切都很好。但是,D3 插值器实际上是(双关语)从 "20%"
插值到 "calc(80% - 3rem)"
。当然,插值器不知道如何处理这个,它实际上是从 "calc(20% - 3rem)"
插值到 "calc(80% - 3rem)"
.
让我们看看:
const interpolator = d3.interpolate("20%", "calc(80% - 3rem)");
d3.range(0, 1.1, 0.1).forEach(d => {
console.log(interpolator(d))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
最简单的解决方案是评估 calc()
的结果并在插值器中使用该值。有几种方法可以做到这一点,比如使用 this library.
因此,假设在评估之后我们有一些值,例如 150px
和 430px
。现在插值很容易:
const interpolator = d3.interpolate("150px", "430px");
d3.range(0, 1.1, 0.1).forEach(d => {
console.log(interpolator(d))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
由于 d3s 字符串插值使用第二个输入(生成的字符串)作为模板,并将它找到的任何数字与第一个输入的对应数字(按索引匹配)进行插值,因此可以避免评估 css 通过对两个值进行插值来手动计算:
calc(20% - 0rem)