使用ArcTween为d3.js

时间:2016-03-11 17:39:14

标签: javascript d3.js

目前正试图在d3.js中设置PieChart的绘制动画,而我目前在使用ArcTween函数方面遇到了困难,继承我的代码:

   <!doctype HTML>
    <html>
        <head>
            <title>Page Title</title>
            <meta charset="UTF-8">

            <script type="text/javascript" src="js/d3.min.js"></script>
            <link rel="stylesheet" type="text/css" href="css/style.css">

        </head>
        <body>

            <script type="text/javascript">

     //=========================================================================================================================================
     // initializing variables 


                var data = []; // empty array to hold the objects imported from the JSON file
                var oRadius = 300; //var holding value for the outer radius of the arc
                var iRadius = 80;  //var holding the value for the inner radius of the arc
                var cRadius = 3;   //var holding the value for the corner radius of the arc
                var colors = d3.scale.category20b();//built in D3 function to color pieces of data
                var width = 1400; //setting the width of the svg
                var height = 1000; //setting the height of the svg
                var dRadius = 5; //setting the radius for the dots
                var sColor = "white"; // color for the stroke of the arcs
                var dStrokeColor = "#666"; // stroke color for the dots
                var dFillColor  = "#ccc" // fill color for the dots
                var fontSize = 25; // font size value for the text labels
                var numFont = 15; // font size for the number labels
                var linePadding = 160; // value to translate the text and number labels to the end of each polyLine




                var myArcMaker= d3.svg.arc().outerRadius(oRadius).innerRadius(iRadius).cornerRadius(cRadius); //var that returns the values needed to create the arcs of the pie chart            
                var bigArcMaker=  d3.svg.arc().outerRadius(400).innerRadius(oRadius).cornerRadius(cRadius); //var that returns the values needed to create the arcs of the big pie chart used to draw the polylines            

                var  mySvg =  d3.select('body') //select the html body in the DOM
                              .append('svg') // place an empty svg in the body
                              .attr('width', width) //give the svg this width
                              .attr("height", height)//give the svg this height
                              .append("g")//append a group to the svg
                              .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")// centers the pie chart in the center of the svg this will make sure everything in the group is centered 


                               mySvg.append("g") //creates a group
                               .attr("class", "slices"); // give it a class of slices, used for the pie chart arcs
                               mySvg.append("g") // creates a group
                               .attr("class", "dots"); // give it a class of dots, used for the circles in the centre of the arcs
                                mySvg.append("g")//creates a group
                               .attr("class", "lines");// give it a class of lines, used for the big pie chart surrounding the main piechart
                                mySvg.append("g")//creates a group
                               .attr("class", "polyLines");//gives it a class of polylines, used for the polylines protruding it from the pie chart arcs
                                mySvg.append("g")//creates a group
                               .attr("class", "labels");//gives a class of labels, used for the text labels at the end of the polylines
                                 mySvg.append("g")//creates a group
                               .attr("class", "numlabels");//gives it a class of numlabels, used for the number labels at the end of the polylines




                var myPie =  d3.layout.pie()
                             .sort(null) //removes any d3 sorting 
                            .startAngle((Math.PI)/360) // setting the start angle for the arcs
                            .endAngle((2*(Math.PI))) // setting the end angle for the arcs
                            .padAngle(2*(2*(Math.PI))/360).value(function(d){return d.value}); //setting the values for that start angle, end angle and pad angle for the arcs and takes in the the values from the objects in the data array

    //======================================================================================================================================================


                     d3.json("data.json", function (json) // importing the json file
                    {

                        data = json; // setting the empty data array equal to the values of the objects in the json file
                        visual(); // this function holds all the d3 code to create the arc

                    })



    //======================================================================================================================================================

                function visual() // this function prevents the code that creates the arc from running before the objects from the json file are added into the empty data array
                {

                  //  console.log(data); // checking to see if the objects are loaded into the data ray using the console in chrome








                    var slice = mySvg.select("g.slices") //selecting the class slices
                      .selectAll("path.slice")//selecting all paths in the slice class
                      .data(myPie(data))//binds the data to the DOM elements 
                      .enter()//begin looping through the data
                      .append("path")//append a path
                      .attr("class", "slice")//give it a class of slice
                      .attr("d", function(d) {//runs the data in the dataset through the arcmaker function
                        return myArcMaker(d)
                      })
                      .attr("fill", function(d, i) {
                        return colors(i);
                      }) //using the d3 color brewer to color each arc
                      .each(function(d) { this._current = d; })
                      .attr("stroke", "white") //giving each arc a stroke of white
                      .style('stroke-width',2) //gives the stroke a width of 2px
                      .each(function(d) { this._current = d; })
                      .transition().duration(750).attrTween("d", arcTween); // redraw the arcs




                    var dots = mySvg.select("g.dots") //select the group dots
                      .selectAll("cirlces") //select all circles in the dots group
                      .data(myPie(data))//binds the data to the DOM elements
                      .enter()//begin the loop
                      .append("circle")//draw a circle
                      .attr("class", "g.dots")//gives it a class of dots
                      .attr("transform", function(d)//transform each circle to the centre of each arc using the .centroid method
                      {
                        return "translate(" + myArcMaker.centroid(d) + ")"; 
                      })
                      .attr("r", dRadius)//setting the radius of the circle
                      .attr("fill", dFillColor)//setting the fill color
                      .attr("stroke", sColor)//setting the stroke color
    //                
                    var lines = mySvg.select(".lines") //select the lines class                         *--------------------------------------*
                      .selectAll("path.lines")//select all paths in the lines class                     * This section here is to draw         *
                      .data(myPie(data)) //binds the data to the DOM elements                           * the invisible piechart that          * 
                      .enter()//begin the loop                                                          * surrounds the smaller piechart this  * 
                      .append("path")//draw a path                                                      * used for the polylines later on      *
                      .attr("class", "lines")//give it a class of lines                                 *--------------------------------------*
                      .attr("d", function(d) {//set the d value to the values returned from the bigArcMaker function
                        return bigArcMaker(d)
                      }).attr("fill", "none")//give the fill a value of none
                      .attr("stroke", "none")//give the stroke a value of none


    //                var outerDots =  mySvg.select("g.dots")//select the dots group
    //                  .selectAll("cirlces")//select all circles in the dots group
    //                  .data(myPie(data))//binds the data to the DOM elements
    //                  .enter()
    //                  .append("circle")//create a circle
    //                  .attr("class", "g.dots")//give it a class of dots
    //                  .attr("transform", function(d)//translate it to the centroid of the bigArc surrounding the main pie chart
    //                  {
    //                    return "translate(" + bigArcMaker.centroid(d) + ")"; 
    //                  })
    //                  .attr("r", dRadius)          
    //                  .attr("fill", dFillColor)
    //                  .attr("stroke", sColor)






    //                    var x1 = myArcMaker.centroid(d)[0];
    //                    var y1 = myArcMaker.centroid(d)[1];
    //                    var x2 = bigArcMaker.centroid(d)[0];
    //                    var y2 = bigArcMaker.centroid(d)[1];
    //                    var x3 = function(d){if(x2<0){return bigArcMaker.centroid(d)[0]-160}}

    //                    var lineData = [{'x': x1},
    //                                   ]


                        var polyLines = mySvg.select(".polyLines")//select the class of polylines
                        .selectAll("polylines")//sellect all polylines in the class of polylines
                        .data(myPie(data))//binds the data to the DOM elements
                        .enter()
                        .append("polyline")//create a polyline
                        .attr("class", "polyLines")//give it a class of polylines
                        .attr("points", function(d) {//set the points for the polylines
                          var p = " "; //used because i was getting errors with my strings also makes this the conditional statement more readable
                          p += myArcMaker.centroid(d)[0] + ',' + myArcMaker.centroid(d)[1] + ',' + bigArcMaker.centroid(d)[0] + ',' + bigArcMaker.centroid(d)[1] + ',';
                          p += bigArcMaker.centroid(d)[0] < 0 ? bigArcMaker.centroid(d)[0] - linePadding : bigArcMaker.centroid(d)[0] + linePadding; //if the x value for the bigArc maker is less than zero - linePadding, if its greater, add linePading
                          p +=  ',' + bigArcMaker.centroid(d)[1];
                          return p;

                        })
                       .attr("fill", "none")//gives the fill value none
                       .attr("stroke", sColor) //gives the stroke a color of sColor
                       .style('stroke-width',2)//gives the stroke-width of 2 pixels



                        var labels = mySvg.select(".labels")//select class labels
                                    .selectAll("text")//select all text
                                    .data(myPie(data))//binds the data to the DOM elements
                                    .enter()
                                    .append("text")//create a text
                                    .text(function(d) //setting the text value to the Fruits label in the dataset
                                    {
                                    return d.data.Fruits;
                                    })
                                    .style("fill", sColor)//sets the fill to the sColor attribute
                                    .attr("x", function(d)//conditional statement that determines where the text will be placed, similar to the polylines
                                        {
                                        if(bigArcMaker.centroid(d)[0]>0)
                                        {
                                         return bigArcMaker.centroid(d)[0]+linePadding;
                                        }
                                        else
                                        {
                                         return bigArcMaker.centroid(d)[0]-linePadding;
                                        }

                                          })
                                        .attr("y", function(d){return bigArcMaker.centroid(d)[1]})//set the why value to the y value of the centroid array
                                        .attr("text-anchor", function(d){
                                              if(bigArcMaker.centroid(d)>0)//conditional statement that sets the text anchor for each piece of text, similar to polylines 

                                            {
                                                return "start"
                                            }
                                              else{
                                                  return "end"
                                              }


                                            })
                                            .attr("font-family", "Helvetica") // sets the font family
                                            .style("font-size", fontSize)//sets the font size




                        var numLabels = mySvg.select(".numlabels") //select the class numlabels
                                    .selectAll("text")//selects all text in the class numlabels
                                    .data(myPie(data))//binds the data to the DOM elements
                                    .enter()
                                    .append("text")//append a text
                                    .text(function(d) //sets the value of the text to the value attribute in the dataset array
                                    {
                                    return d.data.value;
                                    })
                                    .style("fill", sColor)//sets the fill color
                                    .attr("x", function(d)//conditional statement to set the x value of the text similar to the polylines and labels
                                        {
                                        if(bigArcMaker.centroid(d)[0]>0)
                                        {
                                         return bigArcMaker.centroid(d)[0]+linePadding;
                                        }
                                        else
                                        {
                                         return bigArcMaker.centroid(d)[0]-linePadding;
                                        }

                                          })
                                        .attr("y", function(d){return bigArcMaker.centroid(d)[1]})//set the why value to the y value of the centroid array
                                         .attr("text-anchor", function(d){
                                              if(bigArcMaker.centroid(d)>0)//conditional statement that sets the text anchor for each piece of text, similar to polylines 

                                            {
                                                return "start"
                                            }
                                              else{
                                                  return "end"
                                              }


                                            })
                                        .attr("dy", 20)
                                        .attr("font-family", "Helvetica") // sets the font family
                                        .style("font-size", numFont)



                     function arcTween(a)
                    {
                      var i = d3.interpolate(this._current, a);
                      this._current = i(0);
                      return function(t)
                      {
                       return myArcMaker(i(t));
                     };
                    }
                }



            </script>
        </body>
    </html>

我希望它从开始角度开始并绘制到结束角度,我尝试使用d.startAngle和d.endAngle但是当我在chrome中检查它时,我得到一个未被捕获的引用错误,因为d未定义。目前代码正在编译,当我检查它时我没有错误,我不太确定它是如何工作的,所以探索会很棒

继承我的JSFiddle:http://jsfiddle.net/JamieHyland1/gyekfnr2/

1 个答案:

答案 0 :(得分:0)

你很近,你的补间功能有点偏差。此外,您可以废弃所有this._current内容,只在补间函数本身中进行闭包。

  function arcTween(a) { //<-- a is the datum bound to each arc
    var startAngle = a.startAngle; //<-- keep reference to start angle
    var i = d3.interpolate(a.startAngle, a.endAngle); //<-- interpolate start to end
    return function(t) {
      return myArcMaker({ //<-- return arc at each iteration from start to interpolate end
        startAngle: startAngle,
        endAngle: i(t)
      });
    };
  }

您将此称为:

var slice = mySvg.select("g.slices") //selecting the class slices
    .selectAll("path.slice") //selecting all paths in the slice class
    .data(myPie(data)) //binds the data to the DOM elements 
    .enter() //begin looping through the data
    .append("path") //append a path
    .attr("class", "slice") //give it a class of slice
    .attr("fill", function(d, i) {
      return colors(i);
    }) //using the d3 color brewer to color each arc
    .attr("stroke", "white") //giving each arc a stroke of white
    .style('stroke-width', 2) //gives the stroke a width of 2px
    .transition().duration(750).attrTween("d", arcTween); // redraw the arcs

完整代码:

<!DOCTYPE html>
<html>

<head>
  <title>Page Title</title>
  <meta charset="UTF-8" />
  <script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>

<body>
  <script type="text/javascript">
    //=========================================================================================================================================
    // initializing variables 


    var data = []; // empty array to hold the objects imported from the JSON file
    var oRadius = 300; //var holding value for the outer radius of the arc
    var iRadius = 80; //var holding the value for the inner radius of the arc
    var cRadius = 3; //var holding the value for the corner radius of the arc
    var colors = d3.scale.category20b(); //built in D3 function to color pieces of data
    var width = 1400; //setting the width of the svg
    var height = 1000; //setting the height of the svg
    var dRadius = 5; //setting the radius for the dots
    var sColor = "white"; // color for the stroke of the arcs
    var dStrokeColor = "#666"; // stroke color for the dots
    var dFillColor = "#ccc" // fill color for the dots
    var fontSize = 25; // font size value for the text labels
    var numFont = 15; // font size for the number labels
    var linePadding = 160; // value to translate the text and number labels to the end of each polyLine




    var myArcMaker = d3.svg.arc().outerRadius(oRadius).innerRadius(iRadius).cornerRadius(cRadius); //var that returns the values needed to create the arcs of the pie chart            
    var bigArcMaker = d3.svg.arc().outerRadius(400).innerRadius(oRadius).cornerRadius(cRadius); //var that returns the values needed to create the arcs of the big pie chart used to draw the polylines            

    var mySvg = d3.select('body') //select the html body in the DOM
      .append('svg') // place an empty svg in the body
      .attr('width', width) //give the svg this width
      .attr("height", height) //give the svg this height
      .append("g") //append a group to the svg
      .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")") // centers the pie chart in the center of the svg this will make sure everything in the group is centered 


    mySvg.append("g") //creates a group
      .attr("class", "slices"); // give it a class of slices, used for the pie chart arcs
    mySvg.append("g") // creates a group
      .attr("class", "dots"); // give it a class of dots, used for the circles in the centre of the arcs
    mySvg.append("g") //creates a group
      .attr("class", "lines"); // give it a class of lines, used for the big pie chart surrounding the main piechart
    mySvg.append("g") //creates a group
      .attr("class", "polyLines"); //gives it a class of polylines, used for the polylines protruding it from the pie chart arcs
    mySvg.append("g") //creates a group
      .attr("class", "labels"); //gives a class of labels, used for the text labels at the end of the polylines
    mySvg.append("g") //creates a group
      .attr("class", "numlabels"); //gives it a class of numlabels, used for the number labels at the end of the polylines




    var myPie = d3.layout.pie()
      .sort(null) //removes any d3 sorting 
      .startAngle((Math.PI) / 360) // setting the start angle for the arcs
      .endAngle((2 * (Math.PI))) // setting the end angle for the arcs
      .padAngle(2 * (2 * (Math.PI)) / 360).value(function(d) {
        return d.value
      }); //setting the values for that start angle, end angle and pad angle for the arcs and takes in the the values from the objects in the data array

    //======================================================================================================================================================


    //  d3.json("data.json", function (json) // importing the json file
    // {

    data = [{
      value: 10
    }, {
      value: 20
    }, {
      value: 30
    }];
    visual(); // this function holds all the d3 code to create the arc

    // })



    //======================================================================================================================================================

    function visual() // this function prevents the code that creates the arc from running before the objects from the json file are added into the empty data array
    {

      //  console.log(data); // checking to see if the objects are loaded into the data ray using the console in chrome








      var slice = mySvg.select("g.slices") //selecting the class slices
        .selectAll("path.slice") //selecting all paths in the slice class
        .data(myPie(data)) //binds the data to the DOM elements 
        .enter() //begin looping through the data
        .append("path") //append a path
        .attr("class", "slice") //give it a class of slice
        .attr("fill", function(d, i) {
          return colors(i);
        }) //using the d3 color brewer to color each arc
        .attr("stroke", "white") //giving each arc a stroke of white
        .style('stroke-width', 2) //gives the stroke a width of 2px
        .transition().duration(750).attrTween("d", arcTween); // redraw the arcs




      var dots = mySvg.select("g.dots") //select the group dots
        .selectAll("cirlces") //select all circles in the dots group
        .data(myPie(data)) //binds the data to the DOM elements
        .enter() //begin the loop
        .append("circle") //draw a circle
        .attr("class", "g.dots") //gives it a class of dots
        .attr("transform", function(d) //transform each circle to the centre of each arc using the .centroid method
          {
            return "translate(" + myArcMaker.centroid(d) + ")";
          })
        .attr("r", dRadius) //setting the radius of the circle
        .attr("fill", dFillColor) //setting the fill color
        .attr("stroke", sColor) //setting the stroke color
        //                
      var lines = mySvg.select(".lines") //select the lines class                         *--------------------------------------*
        .selectAll("path.lines") //select all paths in the lines class                     * This section here is to draw         *
        .data(myPie(data)) //binds the data to the DOM elements                           * the invisible piechart that          * 
        .enter() //begin the loop                                                          * surrounds the smaller piechart this  * 
        .append("path") //draw a path                                                      * used for the polylines later on      *
        .attr("class", "lines") //give it a class of lines                                 *--------------------------------------*
        .attr("d", function(d) { //set the d value to the values returned from the bigArcMaker function
          return bigArcMaker(d)
        }).attr("fill", "none") //give the fill a value of none
        .attr("stroke", "none") //give the stroke a value of none


      //                var outerDots =  mySvg.select("g.dots")//select the dots group
      //                  .selectAll("cirlces")//select all circles in the dots group
      //                  .data(myPie(data))//binds the data to the DOM elements
      //                  .enter()
      //                  .append("circle")//create a circle
      //                  .attr("class", "g.dots")//give it a class of dots
      //                  .attr("transform", function(d)//translate it to the centroid of the bigArc surrounding the main pie chart
      //                  {
      //                    return "translate(" + bigArcMaker.centroid(d) + ")"; 
      //                  })
      //                  .attr("r", dRadius)          
      //                  .attr("fill", dFillColor)
      //                  .attr("stroke", sColor)






      //                    var x1 = myArcMaker.centroid(d)[0];
      //                    var y1 = myArcMaker.centroid(d)[1];
      //                    var x2 = bigArcMaker.centroid(d)[0];
      //                    var y2 = bigArcMaker.centroid(d)[1];
      //                    var x3 = function(d){if(x2<0){return bigArcMaker.centroid(d)[0]-160}}

      //                    var lineData = [{'x': x1},
      //                                   ]


      var polyLines = mySvg.select(".polyLines") //select the class of polylines
        .selectAll("polylines") //sellect all polylines in the class of polylines
        .data(myPie(data)) //binds the data to the DOM elements
        .enter()
        .append("polyline") //create a polyline
        .attr("class", "polyLines") //give it a class of polylines
        .attr("points", function(d) { //set the points for the polylines
          var p = " "; //used because i was getting errors with my strings also makes this the conditional statement more readable
          p += myArcMaker.centroid(d)[0] + ',' + myArcMaker.centroid(d)[1] + ',' + bigArcMaker.centroid(d)[0] + ',' + bigArcMaker.centroid(d)[1] + ',';
          p += bigArcMaker.centroid(d)[0] < 0 ? bigArcMaker.centroid(d)[0] - linePadding : bigArcMaker.centroid(d)[0] + linePadding; //if the x value for the bigArc maker is less than zero - linePadding, if its greater, add linePading
          p += ',' + bigArcMaker.centroid(d)[1];
          return p;

        })
        .attr("fill", "none") //gives the fill value none
        .attr("stroke", sColor) //gives the stroke a color of sColor
        .style('stroke-width', 2) //gives the stroke-width of 2 pixels



      var labels = mySvg.select(".labels") //select class labels
        .selectAll("text") //select all text
        .data(myPie(data)) //binds the data to the DOM elements
        .enter()
        .append("text") //create a text
        .text(function(d) //setting the text value to the Fruits label in the dataset
          {
            return d.data.Fruits;
          })
        .style("fill", sColor) //sets the fill to the sColor attribute
        .attr("x", function(d) //conditional statement that determines where the text will be placed, similar to the polylines
          {
            if (bigArcMaker.centroid(d)[0] > 0) {
              return bigArcMaker.centroid(d)[0] + linePadding;
            } else {
              return bigArcMaker.centroid(d)[0] - linePadding;
            }

          })
        .attr("y", function(d) {
          return bigArcMaker.centroid(d)[1]
        }) //set the why value to the y value of the centroid array
        .attr("text-anchor", function(d) {
          if (bigArcMaker.centroid(d) > 0) //conditional statement that sets the text anchor for each piece of text, similar to polylines 

          {
            return "start"
          } else {
            return "end"
          }


        })
        .attr("font-family", "Helvetica") // sets the font family
        .style("font-size", fontSize) //sets the font size




      var numLabels = mySvg.select(".numlabels") //select the class numlabels
        .selectAll("text") //selects all text in the class numlabels
        .data(myPie(data)) //binds the data to the DOM elements
        .enter()
        .append("text") //append a text
        .text(function(d) //sets the value of the text to the value attribute in the dataset array
          {
            return d.data.value;
          })
        .style("fill", sColor) //sets the fill color
        .attr("x", function(d) //conditional statement to set the x value of the text similar to the polylines and labels
          {
            if (bigArcMaker.centroid(d)[0] > 0) {
              return bigArcMaker.centroid(d)[0] + linePadding;
            } else {
              return bigArcMaker.centroid(d)[0] - linePadding;
            }

          })
        .attr("y", function(d) {
          return bigArcMaker.centroid(d)[1]
        }) //set the why value to the y value of the centroid array
        .attr("text-anchor", function(d) {
          if (bigArcMaker.centroid(d) > 0) //conditional statement that sets the text anchor for each piece of text, similar to polylines 

          {
            return "start"
          } else {
            return "end"
          }


        })
        .attr("dy", 20)
        .attr("font-family", "Helvetica") // sets the font family
        .style("font-size", numFont)



      function arcTween(a) {
        var startAngle = a.startAngle;
        var i = d3.interpolate(a.startAngle, a.endAngle);
        return function(t) {
          return myArcMaker({
            startAngle: startAngle,
            endAngle: i(t)
          });
        };
      }
    }
  </script>
</body>

</html>