D3过渡意外地起作用

时间:2017-10-29 19:37:52

标签: 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]))

1 个答案:

答案 0 :(得分:4)

这里的问题只是转换使用的插值。

D3可以插入两个字符串而没有任何问题,例如300px20px。但是,在您的情况下,起始字符串具有"%",而最终字符串具有"px"。 D3无法插入,这是非常可原谅的:从"%""px"的过渡是什么?

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

  

返回两个字符串a和b之间的插值器。字符串插值器查找嵌入在a和b中的数字,其中每个数字都是JavaScript理解的形式。

在第一个演示中,两个字符串都有"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>
&#13;
&#13;
&#13;

如你所见,效果不错。

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

&#13;
&#13;
var interpolator = d3.interpolateString("100%", "0px");
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;
&#13;
&#13;

如您所见,在第一次插值时,"%"将转换为"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]);

以下是您更改的代码:

&#13;
&#13;
<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>
&#13;

import re
to_sub = 'parameter Modelica.SIunits.Height Hfsc = 3.7 "ground floor"'
replacement = 'parameter Modelica.SIunits.Height Height_1 = 2 "ground floor"'
with open(in_path, 'r') as inf, open(out_path, 'w') as outf:
    for line in inf:
        subbed_line = re.sub(to_sub, replacement, line)
        outf.write(subbed_line)
&#13;
&#13;
&#13;