【问题标题】:d3 arc transition anticlockwise not clockwised3 逆时针非顺时针圆弧过渡
【发布时间】:2017-02-14 00:56:49
【问题描述】:

我正在寻找两个动画甜甜圈图,需要以某种方式对其进行动画处理。

如果你看一下 jsfiddle:

https://jsfiddle.net/5uc1xfxm/

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <meta name="robots" content="noindex, nofollow">
  <meta name="googlebot" content="noindex, nofollow">

<script type="text/javascript" src="/js/lib/dummy.js"></script>

<link rel="stylesheet" type="text/css" href="/css/result-light.css">

<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>

    <style type="text/css">
    .animated-ring {
  margin-left: auto;
  margin-right: auto;
  //margin-top: 50px;
  width: 200px;
  background-color: #fff;
}
  </style>

<script type='text/javascript'>//<![CDATA[
window.onload=function(){
var tau = 2 * Math.PI; // http://tauday.com/tau-manifesto

// An arc function with all values bound except the endAngle. So, to compute an
// SVG path string for a given angle, we pass an object with an endAngle
// property to the `arc` function, and it will return the corresponding string.
var arc1 = d3.arc()
  .innerRadius(45)
  .outerRadius(90)
  .startAngle(0.75 * tau);

var arc2 = d3.arc()
  .innerRadius(45)
  .outerRadius(90)
  .startAngle(0.25 * tau);

// Get the SVG container, and apply a transform such that the origin is the
// center of the canvas. This way, we don’t need to position arcs individually.
var svg1 = d3.select("#anim1"),
  width = +svg1.attr("width"),
  height = +svg1.attr("height"),
  g = svg1.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

var svg2 = d3.select("#anim2"),
  width = +svg2.attr("width"),
  height = +svg2.attr("height"),
  h = svg2.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

// Add the background arc, from 0 to 100% (tau).
var background1 = g.append("path")
  .datum({
    endAngle: tau
  })
  .style("fill", "transparent")
  .attr("d", arc1);

var background2 = h.append("path")
  .datum({
    endAngle: tau
  })
  .style("fill", "transparent")
  .attr("d", arc2);

// Add the foreground arc in orange, currently showing 12.7%.
var foreground1 = g.append("path")
  .datum({
    endAngle: 0.75 * tau
  })
  .style("fill", "#EF4939")
  .attr("d", arc1);

var foreground2 = h.append("path")
  .datum({
    endAngle: 0.25 * tau
  })
  .style("fill", "blue")
  .attr("d", arc2);

// Every so often, start a transition to a new random angle. The attrTween
// definition is encapsulated in a separate function (a closure) below.
d3.timer(function() {
  foreground1.transition()
    .duration(75)
    .attrTween("d", arcTween(0 * tau));
  foreground2.transition()
    .duration(75)
    .attrTween("d", arcTween2(0.5 * tau));
});

// Returns a tween for a transition’s "d" attribute, transitioning any selected
// arcs from their current angle to the specified new angle.
function arcTween(newAngle) {

  // The function passed to attrTween is invoked for each selected element when
  // the transition starts, and for each element returns the interpolator to use
  // over the course of transition. This function is thus responsible for
  // determining the starting angle of the transition (which is pulled from the
  // element’s bound datum, d.endAngle), and the ending angle (simply the
  // newAngle argument to the enclosing function).
  return function(d) {

    // To interpolate between the two angles, we use the default d3.interpolate.
    // (Internally, this maps to d3.interpolateNumber, since both of the
    // arguments to d3.interpolate are numbers.) The returned function takes a
    // single argument t and returns a number between the starting angle and the
    // ending angle. When t = 0, it returns d.endAngle; when t = 1, it returns
    // newAngle; and for 0 < t < 1 it returns an angle in-between.
    var interpolate = d3.interpolate(d.endAngle, newAngle);

    // The return value of the attrTween is also a function: the function that
    // we want to run for each tick of the transition. Because we used
    // attrTween("d"), the return value of this last function will be set to the
    // "d" attribute at every tick. (It’s also possible to use transition.tween
    // to run arbitrary code for every tick, say if you want to set multiple
    // attributes from a single function.) The argument t ranges from 0, at the
    // start of the transition, to 1, at the end.
    return function(t) {

      // Calculate the current arc angle based on the transition time, t. Since
      // the t for the transition and the t for the interpolate both range from
      // 0 to 1, we can pass t directly to the interpolator.
      //
      // Note that the interpolated angle is written into the element’s bound
      // data object! This is important: it means that if the transition were
      // interrupted, the data bound to the element would still be consistent
      // with its appearance. Whenever we start a new arc transition, the
      // correct starting angle can be inferred from the data.
      d.endAngle = interpolate(t);

      // Lastly, compute the arc path given the updated data! In effect, this
      // transition uses data-space interpolation: the data is interpolated
      // (that is, the end angle) rather than the path string itself.
      // Interpolating the angles in polar coordinates, rather than the raw path
      // string, produces valid intermediate arcs during the transition.
      return arc1(d);
    };
  };
}

// Returns a tween for a transition’s "d" attribute, transitioning any selected
// arcs from their current angle to the specified new angle.
function arcTween2(newAngle) {
  return function(d) {
    var interpolate = d3.interpolate(d.endAngle, newAngle);
    return function(t) {
            d.endAngle = interpolate(t);
      return arc2(d);
    };
  };
}
}//]]> 

</script>


</head>

<body>
  <div class="animated-ring">
  <svg width="200" height="200" id="anim1"></svg>
  <svg width="200" height="200" id="anim2"></svg>
</div>

  <script>
  // tell the embed parent frame the height of the content
  if (window.parent && window.parent.parent){
    window.parent.parent.postMessage(["resultsFrame", {
      height: document.body.getBoundingClientRect().height,
      slug: "5uc1xfxm"
    }], "*")
  }
</script>

</body>

</html>

您将看到两个动画。橙色图表按要求工作,但蓝色图表没有。

开始和结束位置是正确的,但不是顺时针移动并且只填充了四分之一圆。我需要它逆时针移动并填满圆的四分之三。

有什么想法吗?

【问题讨论】:

    标签: javascript jquery d3.js


    【解决方案1】:

    假设我理解问题,

    不要让圆弧从 0.25 tau 过渡到 0.5 tau,而是尝试 -0.5 tau:

    .attrTween("d", arcTween2(-0.5 * tau));
    

    这将向后移动圆弧并使其填充整个甜甜圈的 3/4。这符合第一个行为正常的甜甜圈的模式,其中最终结束角度小于开始角度。

    更新小提琴here

    还有一个使用你的代码的 sn-p (我已经改变了甜甜圈的顺序,所以你不需要快速滚动):

    <!DOCTYPE html>
    <html>
    <head>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <meta name="robots" content="noindex, nofollow">
      <meta name="googlebot" content="noindex, nofollow">
    
    <script type="text/javascript" src="/js/lib/dummy.js"></script>
    
    <link rel="stylesheet" type="text/css" href="/css/result-light.css">
    
    <script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
    
        <style type="text/css">
        .animated-ring {
      margin-left: auto;
      margin-right: auto;
      //margin-top: 50px;
      width: 200px;
      background-color: #fff;
    }
      </style>
    
    <script type='text/javascript'>//<![CDATA[
    window.onload=function(){
    var tau = 2 * Math.PI; // http://tauday.com/tau-manifesto
    
    // An arc function with all values bound except the endAngle. So, to compute an
    // SVG path string for a given angle, we pass an object with an endAngle
    // property to the `arc` function, and it will return the corresponding string.
    var arc1 = d3.arc()
      .innerRadius(45)
      .outerRadius(90)
      .startAngle(0.75 * tau);
    
    var arc2 = d3.arc()
      .innerRadius(45)
      .outerRadius(90)
      .startAngle(0.25 * tau);
    
    // Get the SVG container, and apply a transform such that the origin is the
    // center of the canvas. This way, we don’t need to position arcs individually.
    var svg1 = d3.select("#anim1"),
      width = +svg1.attr("width"),
      height = +svg1.attr("height"),
      g = svg1.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    
    var svg2 = d3.select("#anim2"),
      width = +svg2.attr("width"),
      height = +svg2.attr("height"),
      h = svg2.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    
    // Add the background arc, from 0 to 100% (tau).
    var background1 = g.append("path")
      .datum({
        endAngle: tau
      })
      .style("fill", "transparent")
      .attr("d", arc1);
    
    var background2 = h.append("path")
      .datum({
        endAngle: tau
      })
      .style("fill", "transparent")
      .attr("d", arc2);
    
    // Add the foreground arc in orange, currently showing 12.7%.
    var foreground1 = g.append("path")
      .datum({
        endAngle: 0.75 * tau
      })
      .style("fill", "#EF4939")
      .attr("d", arc1);
    
    var foreground2 = h.append("path")
      .datum({
        endAngle: 0.25 * tau
      })
      .style("fill", "blue")
      .attr("d", arc2);
    
    // Every so often, start a transition to a new random angle. The attrTween
    // definition is encapsulated in a separate function (a closure) below.
    d3.timer(function() {
      foreground1.transition()
        .duration(75)
        .attrTween("d", arcTween(0 * tau));
      foreground2.transition()
        .duration(75)
        .attrTween("d", arcTween2(-0.5 * tau));
    });
    
    // Returns a tween for a transition’s "d" attribute, transitioning any selected
    // arcs from their current angle to the specified new angle.
    function arcTween(newAngle) {
    
      // The function passed to attrTween is invoked for each selected element when
      // the transition starts, and for each element returns the interpolator to use
      // over the course of transition. This function is thus responsible for
      // determining the starting angle of the transition (which is pulled from the
      // element’s bound datum, d.endAngle), and the ending angle (simply the
      // newAngle argument to the enclosing function).
      return function(d) {
    
        // To interpolate between the two angles, we use the default d3.interpolate.
        // (Internally, this maps to d3.interpolateNumber, since both of the
        // arguments to d3.interpolate are numbers.) The returned function takes a
        // single argument t and returns a number between the starting angle and the
        // ending angle. When t = 0, it returns d.endAngle; when t = 1, it returns
        // newAngle; and for 0 < t < 1 it returns an angle in-between.
        var interpolate = d3.interpolate(d.endAngle, newAngle);
    
        // The return value of the attrTween is also a function: the function that
        // we want to run for each tick of the transition. Because we used
        // attrTween("d"), the return value of this last function will be set to the
        // "d" attribute at every tick. (It’s also possible to use transition.tween
        // to run arbitrary code for every tick, say if you want to set multiple
        // attributes from a single function.) The argument t ranges from 0, at the
        // start of the transition, to 1, at the end.
        return function(t) {
    
          // Calculate the current arc angle based on the transition time, t. Since
          // the t for the transition and the t for the interpolate both range from
          // 0 to 1, we can pass t directly to the interpolator.
          //
          // Note that the interpolated angle is written into the element’s bound
          // data object! This is important: it means that if the transition were
          // interrupted, the data bound to the element would still be consistent
          // with its appearance. Whenever we start a new arc transition, the
          // correct starting angle can be inferred from the data.
          d.endAngle = interpolate(t);
    
          // Lastly, compute the arc path given the updated data! In effect, this
          // transition uses data-space interpolation: the data is interpolated
          // (that is, the end angle) rather than the path string itself.
          // Interpolating the angles in polar coordinates, rather than the raw path
          // string, produces valid intermediate arcs during the transition.
          return arc1(d);
        };
      };
    }
    
    // Returns a tween for a transition’s "d" attribute, transitioning any selected
    // arcs from their current angle to the specified new angle.
    function arcTween2(newAngle) {
      return function(d) {
        var interpolate = d3.interpolate(d.endAngle, newAngle);
        return function(t) {
                d.endAngle = interpolate(t);
          return arc2(d);
        };
      };
    }
    }//]]> 
    
    </script>
    
    
    </head>
    
    <body>
      <div class="animated-ring">
      <svg width="200" height="200" id="anim2"></svg>
      <svg width="200" height="200" id="anim1"></svg>
    
    </div>
    
      <script>
      // tell the embed parent frame the height of the content
      if (window.parent && window.parent.parent){
        window.parent.parent.postMessage(["resultsFrame", {
          height: document.body.getBoundingClientRect().height,
          slug: "5uc1xfxm"
        }], "*")
      }
    </script>
    
    </body>
    
    </html>

    【讨论】:

    • 谢谢,这就是你尝试在发烧和生病的孩子编码时得到的结果,你失去了所有明显的逻辑。感谢您帮助我的大脑
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-11
    • 1970-01-01
    • 2013-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多