D3过渡意外地起作用(D3 transition works unexpectedly)

编程入门 行业动态 更新时间:2024-10-25 11:26:07
D3过渡意外地起作用(D3 transition works unexpectedly)

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

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

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

我该怎么办?

实例: 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]))

For some reason, D3 is not transitioning the div's width smoothing on exit.

In the GIF below, I switch between 2 datasets, from [20, 40] to [20]

The expected behavior is that the blue div should shrink smoothly, but instead, it gets stuck.

what should I do differently?

Live example: 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可以毫无问题地插入两个字符串,例如300px到20px 。 但是,在您的情况下,起始字符串具有"%"而最终字符串具有"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> 
  
 

如你所见,结果很好。

现在看看如果第一个字符串有"%"而第二个字符串有"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> 
  
 

The problem here is just the interpolation used by the transition.

D3 can interpolate two strings without any problem, for instance 300px to 20px. However, in your case, the start string has a "%" while the final string has "px". D3 cannot interpolate that, which is quite excusable: what's the transition from "%" to "px"?

Let's show it in the following snippets. Here, I'm using d3.interpolateString(a,b), which:

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.

In the first demo, both strings have "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> 
  
 

As you can see, nice results.

Now look what happens if the first string has "%" while the second one has "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> 
  
 

As you can see, at the very first interpolation, the "%" is converted to "px". That explains the behaviour you're seeing: the div goes from "100%" to "100px" suddenly, and from there to "0px" during the transition time.

Solution:

Change your string to use % in the exit selection:

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

Here is your code with that change:

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> 
  
 

更多推荐

本文发布于:2023-08-07 00:47:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1458564.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:意外地   transition   unexpectedly   works

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!