在D3过渡中分解出重用的属性

时间:2016-09-15 20:14:51

标签: d3.js svg transition

在下面的最小示例中,SVG元素转换为不同的状态,然后恢复为原始状态。如何分解原始属性,以便不必重复? selection.each()transition.each()给了我意想不到的令人困惑的结果。



var circle = d3.select('svg').append('circle')
  .attr('cx', 50) // this part should be factored out
  .attr('cy', 130)
  .attr('r', 25)
  .attr('fill', 'blue');

circle.transition().duration(1000).delay(500)
  .attr('cx', 200)
  .attr('cy', 50)
  .attr('r', 50)
  .attr('fill', 'red')
  .transition().duration(1000).delay(500)
  .attr('cx', 50) // repeated
  .attr('cy', 130)
  .attr('r', 25)
  .attr('fill', 'blue');

<!DOCTYPE html>
<script src="https://d3js.org/d3.v4.min.js"></script>

<svg width='300' height='170'>
</svg>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

一种解决方案可能是利用D3的data binding的力量。您可以定义包含两者的配置对象,稍后要还原的原始值以及元素应转换到的值。通过将此信息绑定到D3创建的DOM元素,您可以在以后的调用中访问它们。这些配置对象可能如下所示:

var circle = [{   // D3 binds data contained in arrays
  orig: {         // The original values
    "cx": 50,
    // ...
  },
  trans: {        // The values to transition to
    "cx": 200,
    // ...
  }
}];

投入d3-selection-multi模块,您可以直接使用上面定义的配置对象,方法是将它们交给selection.attrs()方法:

函数的返回值必须是带有字符串值的对象,然后用于设置当前元素的属性。

// Array of configuration objects
var circle = [{
  orig: {
    "cx": 50,
    "cy": 130,
    "r":  25,
    "fill": "red"
  },
  trans: {
    "cx": 200,
    "cy": 50,
    "r":  50,
    "fill": "blue"
  }
}];

// Create new elements by binding data and using data joins
var circle = d3.select('svg').selectAll('circle')
  .data(circle)                               // Bind configuration objects to elements
  .enter().append('circle')
    .attrs(function(d) { return d.orig; });   // Use the original values

circle.transition().duration(1000).delay(500)
    .attrs(function(d) { return d.trans; })   // Transition to new values
  .transition().duration(1000).delay(500)
    .attrs(function(d) { return d.orig; });   // And transition back to original values
<!DOCTYPE html>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>

<svg width='300' height='170'>
</svg>

答案 1 :(得分:0)

我需要的是call()而不是each()。我知道这是可能的!

function revert(selection) {
  selection
  .attr('cx', 50)
  .attr('cy', 130)
  .attr('r', 25)
  .attr('fill','blue');
}

var circle = d3.select('svg').append('circle')
  .call(revert);

circle.transition().duration(1000).delay(500)
  .attr('cx', 200)
  .attr('cy', 50)
  .attr('r', 50)
  .attr('fill','red')
  .transition().duration(1000).delay(500)
  .call(revert);
<!DOCTYPE html>
<script src="https://d3js.org/d3.v4.min.js"></script>

<svg width='300' height='170'>
</svg>