javascript - D3 过渡工作意外

标签 javascript d3.js string-interpolation

出于某种原因,D3 没有在退出时转换 div 的宽度平滑。

在下面的 GIF 中,我在 2 个数据集之间切换,从 [20, 40][20]

预期的行为是蓝色 div 应该平滑收缩,但它卡住了。

我应该怎么做?

demo

实例: http://jsbin.com/vikodufugo/1/edit?js,output

const render = (data) => {
  const colors = ['red', 'blue', 'green', 'gold'];
  const width = (data) => (d) => (d / d3.max(data)) * 100 + '%';

  const selection = d3
    .select('.chart')
    .selectAll('div')
    .data(data);

  selection
    .transition()
    .duration(750)
    .style('width', width(data))

  selection
    .enter()
    .append('div')
    .style('width', '0px')
    .style('height', '100px')
    .style('background-color', (d, i) => colors[i % colors.length])
    .transition()
      .duration(750)
      .style('width', width(data))

  selection
    .exit()
    .transition()
    .duration(750)
    // shouldn't it transition smoothly?
    .style('width', '0px')
    .remove()
}

...

onClick('#button-1', () => render([20, 40]))
onClick('#button-2', () => render([20]))

最佳答案

这里的问题只是过渡使用的插值。

D3 可以毫无问题地插入两个字符串,例如 300px20px。但是,在您的情况下,起始字符串具有 "%",而最终字符串具有 "px"。 D3 无法对此进行插值,这是情有可原的:从 "%""px" 的转换是什么?

让我们在下面的片段中展示它。在这里,我使用 d3.interpolateString(a,b) ,其中:

Returns an interpolator between the two strings a and b. The string interpolator finds numbers embedded in a and b, where each number is of the form understood by JavaScript.

在第一个demo中,两个字符串都有"px":

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

如您所见,结果不错。

现在看看如果第一个字符串有 "%" 而第二个字符串有 "px" 会发生什么:

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

如您所见,在第一次插值时,"%" 被转换为 "px"。这解释了您所看到的行为:div 突然从 "100%" 变为 "100px",然后从那里变为 "0px" 在过渡期间。

解决方案:

更改您的字符串以在退出选择中使用 %:

selection
    .exit()
    .transition()
    .duration(750) 
    .style('width', '0%')
    //use % here -----^
    .remove()

这里是你的代码有那个变化:

const render = (data) => {
  const colors = ['red', 'blue', 'green', 'gold'];
  const width = (data) => (d) => (d / d3.max(data)) * 100 + '%';

  const selection = d3
    .select('.chart')
    .selectAll('div')
    .data(data);

  selection
    .transition()
    .duration(750)
    .style('width', width(data))

  selection
    .enter()
    .append('div')
    .style('width', '0px')
    .style('height', '100px')
    .style('background-color', (d, i) => colors[i % colors.length])
    .transition()
      .duration(750)
      .style('width', width(data))

  selection
    .exit()
    .transition()
    .duration(750)
    // shouldn't it transition smoothly?
    .style('width', '0%')
    .remove()
}


const onClick = (selector, callback) => (
  document.querySelector(selector).addEventListener('click', callback)
);

onClick('#button-1', () => render([20, 40]))
onClick('#button-2', () => render([20]))

render([20, 40]);
<script src="https://d3js.org/d3.v4.js"></script> 
<div class="buttons">
    <button id="button-1" value="0">Option 1</button>
    <button id="button-2" value="1">Option 2</button>
</div>
<div class="chart"></div>

关于javascript - D3 过渡工作意外,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47004437/

相关文章:

javascript - 如何使用 React Native 创建淡入链动画

javascript - 如何在 Javascript 中有效地匹配和分组字符串?

javascript - d3 节点标签和折叠

javascript - D3 图表 - 圆环图 SVG 中心的图像

javascript - 可重用的 d3.js 组件和继承

javascript - 使用字符串插值进行函数调用

c# - 在 C# 6 字符串插值中对 "{"进行转义

javascript - 如何使用 ES6 模板文字定义 sessionStorage 键

javascript - 删除 Dropzone.js 和 PHP 不起作用的脚本

javascript - 选择其他 radio 时显示/隐藏文本区域 - jQuery 事件未触发