2017-02-14 155 views
2

我正在看有兩個動畫圓環圖,需要以某種方式爲它們製作動畫。d3圓弧轉換逆時針不順時針

如果你看的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> 

你會看到兩個動畫。橙色圖表按需要工作,但藍色圖表不是。

開始和結束位置正確,但不是順時針方向移動,只填充圓的四分之一。我需要它逆時針移動並填充圓的四分之三。

任何想法?

回答

2

假設我理解這個問題,

而不必從0.25頭至0.5頭圓弧過渡,儘量-0.5頭:

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

這將向後移動電弧並導致其填寫整個甜甜圈的3/4。這符合第一個甜圈的模式,該甜圈的行爲正確,最終的終止角度小於起始角度。

更新小提琴here

和使用好措施代碼片段(我已經改變了甜甜圈的順序,所以你不需要快速滾動):

<!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>

+0

謝謝,多數民衆贊成你試圖編碼與發燒和生病的孩子,你失去了所有明顯的邏輯。謝謝你幫助我的大腦 – Dominic